Microsegment.ru
  • Главная страница
  • О проекте
  • Портфолио
  • Блог

Линейная регрессия и шифрование обратной матрицей для защиты персональных данных

Описание проекта

Вам нужно защитить данные клиентов страховой компании «Хоть потоп». Разработайте такой метод преобразования данных, чтобы по ним было сложно восстановить персональную информацию. Обоснуйте корректность его работы.

Нужно защитить данные, чтобы при преобразовании качество моделей машинного обучения не ухудшилось. Подбирать наилучшую модель не требуется.

Инструкция по выполнению проекта

  1. Загрузите и изучите данные.
  2. Ответьте на вопрос и обоснуйте решение.
    1. Признаки умножают на обратимую матрицу. Изменится ли качество линейной регрессии? (Её можно обучить заново.)
    2. Изменится. Приведите примеры матриц.
    3. Не изменится. Укажите, как связаны параметры линейной регрессии в исходной задаче и в преобразованной.
  3. Предложите алгоритм преобразования данных для решения задачи. Обоснуйте, почему качество линейной регрессии не поменяется.
  4. Запрограммируйте этот алгоритм, применив матричные операции. Проверьте, что качество линейной регрессии из sklearn не отличается до и после преобразования. Примените метрику R2.

Описание данных

Набор данных находится в файле /datasets/insurance.csv.

  • Признаки: пол, возраст и зарплата застрахованного, количество членов его семьи.
  • Целевой признак: количество страховых выплат клиенту за последние 5 лет.

Содержание

  • 1  Загрузка данных
  • 2  Умножение матриц
  • 3  Алгоритм преобразования
  • 4  Проверка алгоритма
  • 5  Выводы проекта
  • 6  Чек-лист проверки

Загрузка данных¶

In [1]:
# Базовые библиотеки
import pandas as pd # Датафреймы
import numpy as np # Математика для массивов

# Автоматизация раздельного декодирования признаков
from sklearn.compose import(
    make_column_selector, 
    make_column_transformer, 
    ColumnTransformer
)

# Обработка данных для машинного обучения
# Стандартизация данных
import re
from sklearn.preprocessing import(
    StandardScaler
)

from sklearn.model_selection import(
    train_test_split, # Разделение выборок с целевыми и нецелевыми признаками на обучающую и тестовую
) 

# Метрики (Показатели качества моделей)
from sklearn.metrics import(
    r2_score, # R^2, Коэффициент детерминации (универсальная в %, чувствительная к выбросам, может быть отрицательной и возвращать NaN)
)

# Визуализация графиков
import seaborn as sns
import matplotlib
%matplotlib inline
from matplotlib import pyplot as plt
from matplotlib import rcParams, rcParamsDefault
from pandas.plotting import scatter_matrix
In [2]:
# Отображение всех столбцов таблицы
pd.set_option('display.max_columns', None)
# Обязательно для нормального отображения графиков plt
rcParams['figure.figsize'] = 10, 6
%config InlineBackend.figure_format = 'svg'
# Дополнительно и не обязательно для декорирования графиков
factor = .8
default_dpi = rcParamsDefault['figure.dpi']
rcParams['figure.dpi'] = default_dpi * factor
In [3]:
# Чтение данных из файла
try:
    data = pd.read_csv('/datasets/insurance.csv') 
except:
    data = pd.read_csv('datasets/insurance.csv') 
In [4]:
# Изучение датафрейма
print(data.info()) 
data.head() 
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5000 entries, 0 to 4999
Data columns (total 5 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   Пол                5000 non-null   int64  
 1   Возраст            5000 non-null   float64
 2   Зарплата           5000 non-null   float64
 3   Члены семьи        5000 non-null   int64  
 4   Страховые выплаты  5000 non-null   int64  
dtypes: float64(2), int64(3)
memory usage: 195.4 KB
None
Out[4]:
Пол Возраст Зарплата Члены семьи Страховые выплаты
0 1 41.0 49600.0 1 0
1 0 46.0 38000.0 1 1
2 0 29.0 21000.0 0 0
3 0 21.0 41700.0 2 0
4 1 28.0 26100.0 0 0
In [5]:
# Изучение распределений данных
data.hist();
data.describe() 
Out[5]:
Пол Возраст Зарплата Члены семьи Страховые выплаты
count 5000.000000 5000.000000 5000.000000 5000.000000 5000.000000
mean 0.499000 30.952800 39916.360000 1.194200 0.148000
std 0.500049 8.440807 9900.083569 1.091387 0.463183
min 0.000000 18.000000 5300.000000 0.000000 0.000000
25% 0.000000 24.000000 33300.000000 0.000000 0.000000
50% 0.000000 30.000000 40200.000000 1.000000 0.000000
75% 1.000000 37.000000 46600.000000 2.000000 0.000000
max 1.000000 65.000000 79000.000000 6.000000 5.000000
2023-08-24T22:40:34.806151 image/svg+xml Matplotlib v3.3.4, https://matplotlib.org/
In [6]:
# Количество значений 
# разных страховых выплат
#data['Страховые выплаты'].unique() 
data.groupby(by='Страховые выплаты', axis=0)['Страховые выплаты'].count() 
Out[6]:
Страховые выплаты
0    4436
1     423
2     115
3      18
4       7
5       1
Name: Страховые выплаты, dtype: int64
In [7]:
# Средние значения показателей
# для разного количества страховых выплат
data.groupby(by='Страховые выплаты', axis=0).mean() 
Out[7]:
Пол Возраст Зарплата Члены семьи
Страховые выплаты
0 0.499324 28.970694 39924.752029 1.205816
1 0.468085 44.706856 40260.520095 1.139480
2 0.600000 50.860870 39035.652174 1.017391
3 0.444444 55.833333 37677.777778 0.944444
4 0.571429 60.000000 34057.142857 0.714286
5 1.000000 65.000000 39700.000000 1.000000
In [8]:
# Корреляция значения показателей
data.corr() 
Out[8]:
Пол Возраст Зарплата Члены семьи Страховые выплаты
Пол 1.000000 0.002074 0.014910 -0.008991 0.010140
Возраст 0.002074 1.000000 -0.019093 -0.006692 0.651030
Зарплата 0.014910 -0.019093 1.000000 -0.030296 -0.014963
Члены семьи -0.008991 -0.006692 -0.030296 1.000000 -0.036290
Страховые выплаты 0.010140 0.651030 -0.014963 -0.036290 1.000000

Итоги анализа загруженных данных

  1. Датафрейм содержит 5000 объектов и 5 числовых признаков.
  2. В данных нет пропусков.
  3. Целевой признак содержит 6 категорий от 0 до 5. Вероятнее всего, категории обозначают количество страховых выплат. По мере увеличения значения категории уменьшается количество объектов в ней. Так, в категории 0 содержится 4436 объектов, в категории 1 только 423 объекта, а в категории 5 всего 1 объект.
  4. По мере увеличения количества страховых выплат увеличивается возраст застрахован лица. Эти два показателя имеют сильную положительную корреляцию. При этом, количество страховых выплат почти не зависит от пола и других имеющихся признаков застрахованного лица.
  5. Признаки имеют значительное различие в разбросе числовых значений. Для эффективного использования в обучении их следует стандартизировать.

Умножение матриц¶

В этом задании вы можете записывать формулы в Jupyter Notebook.

Чтобы записать формулу внутри текста, окружите её символами доллара \$; если снаружи — двойными символами \\$\$. Эти формулы записываются на языке вёрстки LaTeX.

Для примера мы записали формулы линейной регрессии. Можете их скопировать и отредактировать, чтобы решить задачу.

Работать в LaTeX необязательно.

Обозначения:

  • $X$ — матрица признаков (нулевой столбец состоит из единиц)

  • $y$ — вектор целевого признака

  • $P$ — матрица, на которую умножаются признаки

  • $w$ — вектор весов линейной регрессии (нулевой элемент равен сдвигу)

Предсказания:

$$ a = Xw $$

Задача обучения:

$$ w = \arg\min_w MSE(Xw, y) $$

Формула обучения:

$$ w = (X^T X)^{-1} X^T y $$

Вопрос:

Признаки умножают на обратимую матрицу. Изменится ли качество линейной регрессии? (Её можно обучить заново.)

Ответ:

Не изменится.

Обоснование:

Если использовать формулу линейной регрессии (https://academy.yandex.ru/handbook/ml/article/linear-models):

$$ a = Xw $$$$ w = (X^T X)^{-1} X^T y $$

то, при умножжении признаков на обратимую матрицу, формула примет вид:

$$ a’ = X’w’ = (XP)w’ $$$$ w’ = ((XP)^T (XP))^{-1} (XP)^T y $$

где $P$ — случайная обратимая матрица. Преобразуем форумлу:

$$ w’ = (X’^T X’)^{-1} X’^T y $$$$ w’ = ((X P)^T (X P))^{-1} (X P)^T y $$$$ w’ = (P^T X^T X P)^{-1} P^T X^T y $$$$ w’ = P^{-1} (X^T X)^{-1} (P^T)^{-1} P^T X^T y $$$$ w’ = P^{-1} (X^T X)^{-1} E X^T y $$$$ w’ = P^{-1} (X^T X)^{-1} X^T y $$$$ w’ = P^{-1} w $$

Т.к. $w’ \not= w$, то и $a’ \not= a$, однако, если $w’$ можно выразить через $P$ и $w$, то и $a’$ можно выразить через $X$, $P$ и $w$:

$$ a’ = X’ w’ $$$$ a’ = (X P) P^{-1} w $$$$ a’ = X P P^{-1} w $$

Алгоритм преобразования¶

Алгоритм

  1. При вызове метода fit() пользовательского класса LinearRegression() внутри метода:
    1. Создать внутриклассовую переменную self.P со случайной обратимой матрицей.
    2. Проверить случайную матрицу на обратимость. Для этого проверить определитель матрицы на равенство нулю. В случае равенства нулю, создать матрицу заново.
    3. Создать переменную X со скалярным произведением обучающей выборки train_features, содержащей все аттрибуты, кроме целевого, на self.P.
    4. Добавить единичный столбец в X.
    5. Создать переменную y, в которую передать данные целевого признака обучающей выборки train_target.
    6. Создать переменную w и записать в нее результаты выполнения формулы $w = (X^T X)^{-1} X^T y$ с использованием одноименных переменных метода fit().
    7. Создать внутриклассовые переменные self.w и self.w0, в которые передать все значения из переменной w, кроме нулевого, и нулевое, соответственно.
  2. При вызове метода predict() пользовательского класса LinearRegression():
    1. Создать переменную X со скалярным произведением обучающей выборки test_features, содержащей все аттрибуты, кроме целевого, на self.P.
    2. Вернуть в качестве предсказания, результаты скалярного произведения переменной X на внутриклассовую переменную self.w, сложенного с внутриклассовой переменной self.w0.

Обоснование

На основании выводов, полученных в пункте 2 данного проекта предполагается, что умножение треннировочной выборки с нецелевыми аттрибутами и аналогичной тестовой выборки на случайную обратимую матрицу даст такой же результат, что и без умножения на подобную матрицу.

Проверка алгоритма¶

In [9]:
# Создание класса "LinearRegression" и его методов
# для предсказания результатов методом линейной регрессии
class LinearRegression:
    
    # Метод, включающий использование 
    # случайной обратимой матрицы для защиты данных
    def keep(self, keeping):
        if keeping == True:
            self.keep = True
        else:
            self.keep = False
    
    # Метод обучения
    def fit(self, train_features, train_target):
        n = 0
        while n == 0:
            self.P = np.random.normal(size=(len(train_features.columns), len(train_features.columns)))
            n = np.linalg.det(self.P) 
        if self.keep == True:
            X = train_features @ self.P
            X = np.concatenate((np.ones((X.shape[0], 1)), X), axis=1)
        else:
            X = np.concatenate((np.ones((train_features.shape[0], 1)), train_features), axis=1)
        y = train_target
        w = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y)
        self.w = w[1:]
        self.w0 = w[0]
    
    # Метод предсказания
    def predict(self, test_features):
        if self.keep == True:
            X = test_features @ self.P
        else:
            X = test_features
        return X.dot(self.w) + self.w0
In [10]:
# Подготовка данных для использования в модели

# Разделение датафрейма на выбоки с целевыми и не целевыми аттрибутами
features = data.drop('Страховые выплаты', axis=1)
target = data['Страховые выплаты']

# Разделение выборок на обучающие и треннировочные
features_train,  features_test, target_train, target_test = train_test_split(
    features, 
    target, 
    test_size=.25, 
    random_state=12345
)

# Стандартизация данных 
scaler = StandardScaler()
scaler.fit(features_train)
features_train = scaler.transform(features_train)
features_test = scaler.transform(features_test)
In [11]:
# Реализаця модели без защиты данных
model = LinearRegression()
model.keep(False)
model.fit(features, target)
predictions = model.predict(features)

pd.DataFrame(
    data={
        'predictions': predictions.values,
        'target': target.values,
    }
).plot(
    kind='hist',  
    alpha=.5, 
    rot=20,
    bins=20
)

r2 = []
r2.append(r2_score(target, predictions))
print('R2:', r2[0])
R2: 0.42494550286668
2023-08-24T22:40:37.090012 image/svg+xml Matplotlib v3.3.4, https://matplotlib.org/
In [12]:
# Реализаця модели с защитой данных
model = LinearRegression()
model.keep(True)
model.fit(features, target)
predictions = model.predict(features)

pd.DataFrame(
    data={
        'predictions': predictions.values,
        'target': target.values,
    }
).plot(
    kind='hist',  
    alpha=.5, 
    rot=20,
    bins=20
)

r2.append(r2_score(target, predictions))
print('R2:', r2[1])
R2: 0.4249455028639104
2023-08-24T22:40:38.696827 image/svg+xml Matplotlib v3.3.4, https://matplotlib.org/
In [13]:
# Разница показателя "R2" между моделями 
# с защищенными и незащищенными данными
print('Показатель R2 моделей:')
print('с защищенными данными  :', r2[1])
print('с незащищенными данными:', r2[0])
print()
print('Разница в показателях  :', r2[1] - r2[0])
Показатель R2 моделей:
с защищенными данными  : 0.4249455028639104
с незащищенными данными: 0.42494550286668

Разница в показателях  : -2.7695623572299155e-12

Вывод из проверки алгоритма

Разница показателя R2 между моделями с защищенными и не защищенными данными стремиться к нулю. Можно сделать вывод о том, что защиту данных с помощью случайной обратимой матрицы допустимо использовать.

Выводы проекта¶

Цель проекта достигнута: обоснован, создан и проверен класс LinearRegression() для предсказания количества страховых случаев с защитой использованных в классе данных путем их умножения на случайную обратимую матрицу. В рамках проекта решены следующие задачи:

  1. Загружены и проанализированы данные.
  2. Найден и обоснован ответ на вопрос о зависимости w и w' с использованием случайной обратимой матрицы.
  3. Предложен и обоснован алгоритм решения данных, используемых в классе LinearRegression(), путем их умножения на случайную обратимую матрицу.
  4. Эксперементально доказана возможнгость использования случайной обратимой матрицы для защиты данных в классе LinearRegression().

Чек-лист проверки¶

Поставьте ‘x’ в выполненных пунктах. Далее нажмите Shift+Enter.

  • [x] Jupyter Notebook открыт
  • [x] Весь код выполняется без ошибок
  • [x] Ячейки с кодом расположены в порядке исполнения
  • [x] Выполнен шаг 1: данные загружены
  • [x] Выполнен шаг 2: получен ответ на вопрос об умножении матриц
    • [x] Указан правильный вариант ответа
    • [x] Вариант обоснован
  • [x] Выполнен шаг 3: предложен алгоритм преобразования
    • [x] Алгоритм описан
    • [x] Алгоритм обоснован
  • [x] Выполнен шаг 4: алгоритм проверен
    • [x] Алгоритм реализован
    • [x] Проведено сравнение качества моделей до и после преобразования

Политика конфиденциальности

Продолжая использовать данный сайт вы подтверждаете свое согласие с условиями его политики конфиденциальности. Подробнее…




Администрация и владельцы данного информационного ресурса не несут ответственности за возможные последствия, связанные с использованием информации, размещенной на нем.


Все права защищены. При копировании материалов сайта обязательно указывать ссылку на © Microsegment.ru (2020-2025)