В чем преимущество numpy?
import numpy as np
Как измерить время выполнения?
A_quick_arr = np.random.normal(size = (100000,))
B_quick_arr = np.random.normal(size = (100000,))
A_slow_list, B_slow_list = list(A_quick_arr), list(B_quick_arr)
def my_sum(a, b):
ans = 0
for i in range(100000):
ans += a[i] * b[i]
return ans
%timeit my_sum(A_quick_arr, B_quick_arr)
10 loops, best of 3: 41.5 ms per loop
%timeit sum([A_slow_list[i] * B_slow_list[i] for i in range(100000)])
10 loops, best of 3: 25.3 ms per loop
%timeit np.sum(A_quick_arr * B_quick_arr)
10000 loops, best of 3: 150 µs per loop
$x = (x^1, ..., x^d)$ — вектор
Векторное пространство $V$ — это множество:
Например: евклидово пространство (вектор — набор вещественных чисел)
Какое отношение имеет к анализу данных? Описывает объект!
Например: задача кредитного скоринга. Объект — человек. Признаки:
Получаем вектор:
$x = (1, 100500, 1, 41, ...)$
А как описать много объектов?
Хотим знать информацию про многих людей (матрица объекты-признаки):
$ X = \begin{pmatrix} 1& 100500& 1& 41& ... \\ 0& 0& 0& 18& ... \\ ...& ...& ...& ...& ... \\ \end{pmatrix}$
Один из векторов можно выразить через другие с помощью линейной комбинаций.
Размерность векторного пространства — максимальное количество линейно независимых векторов в нем.
Как понять что вектора линейно независимы? — Например, вычислить ранг (максимальное число линейно независимых строк/столбцов).
Как искать ранг? [зайдем на википедию]
Выберем первый пункт.
Как привести матрицу к ступенчатому виду?
Элементарными преобразованиями матрицы называются следующие ее преобразования:
Алгоритм решения:
Разделить все элементы ведущей строки на ведущий элемент (преобразование 2 типа). Если ведущая строка последняя, то на этом преобразования следует закончить. 3. К каждой строке, расположенной ниже ведущей, прибавить ведущую строку, умноженную соответственно на такое число, чтобы элементы, стоящие под ведущим оказались равными нулю (преобразование 3 типа). 4. Исключив из рассмотрения строку и столбец, на пересечении которых стоит ведущий элемент, перейти к пункту 1, в котором все описанные действия применяются к оставшейся части матрицы.
Задание: найти ранг матрицы A
$A = \begin{pmatrix} 3 & 1& -1 & -2 & 8 \\ 7 & 1 & -2 & -1 & 12 \\ 11 & 1 & -3 & 0 & 16 \\ 2 & 2 & -1 & -5 & 12 \end{pmatrix}$
[будет на проверочной =)]
Вектор-строка: $w = (w_1, ..., w_d) \in \mathbb{R}^{1 \times d}$
Вектор-столбец: $w = \begin{pmatrix} w_1 \\ ... \\ w_d \end{pmatrix} \in \mathbb{R}^{d \times 1}$
$Xw = y$ (линейная модель)
Количество решений:
Как понять?
Как решать? Метод Гаусса.
Два прохода:
import pandas as pd
Загрузим данные для задачи кредитного скоринга:
data = pd.read_csv('german.data.txt', sep='\t')
data.head()
Status of existing checking account | Duration in month | Credit history | Purpose | Credit amount | Savings account/bonds | Present employment since | Installment rate in percentage of disposable income | Personal status and sex | Other debtors / guarantors | ... | Property | Age in years | Other installment plans | Housing | Number of existing credits at this bank | Job | Number of people being liable to provide maintenance for | Telephone | foreign worker | Credit | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | A11 | 6 | A34 | A43 | 1169 | A65 | A75 | 4 | A93 | A101 | ... | A121 | 67 | A143 | A152 | 2 | A173 | 1 | A192 | A201 | 1 |
1 | A12 | 48 | A32 | A43 | 5951 | A61 | A73 | 2 | A92 | A101 | ... | A121 | 22 | A143 | A152 | 1 | A173 | 1 | A191 | A201 | 2 |
2 | A14 | 12 | A34 | A46 | 2096 | A61 | A74 | 2 | A93 | A101 | ... | A121 | 49 | A143 | A152 | 1 | A172 | 2 | A191 | A201 | 1 |
3 | A11 | 42 | A32 | A42 | 7882 | A61 | A74 | 2 | A93 | A103 | ... | A122 | 45 | A143 | A153 | 1 | A173 | 2 | A191 | A201 | 1 |
4 | A11 | 24 | A33 | A40 | 4870 | A61 | A73 | 3 | A93 | A101 | ... | A124 | 53 | A143 | A153 | 2 | A173 | 2 | A191 | A201 | 2 |
5 rows × 21 columns
Переведем строки в числа:
cat_columns = data.select_dtypes(['object']).columns
data[cat_columns] = data[cat_columns].apply(lambda x: x.astype('category'))
data[cat_columns] = data[cat_columns].apply(lambda x: x.cat.codes)
data.head()
Status of existing checking account | Duration in month | Credit history | Purpose | Credit amount | Savings account/bonds | Present employment since | Installment rate in percentage of disposable income | Personal status and sex | Other debtors / guarantors | ... | Property | Age in years | Other installment plans | Housing | Number of existing credits at this bank | Job | Number of people being liable to provide maintenance for | Telephone | foreign worker | Credit | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 6 | 4 | 4 | 1169 | 4 | 4 | 4 | 2 | 0 | ... | 0 | 67 | 2 | 1 | 2 | 2 | 1 | 1 | 0 | 1 |
1 | 1 | 48 | 2 | 4 | 5951 | 0 | 2 | 2 | 1 | 0 | ... | 0 | 22 | 2 | 1 | 1 | 2 | 1 | 0 | 0 | 2 |
2 | 3 | 12 | 4 | 7 | 2096 | 0 | 3 | 2 | 2 | 0 | ... | 0 | 49 | 2 | 1 | 1 | 1 | 2 | 0 | 0 | 1 |
3 | 0 | 42 | 2 | 3 | 7882 | 0 | 3 | 2 | 2 | 2 | ... | 1 | 45 | 2 | 2 | 1 | 2 | 2 | 0 | 0 | 1 |
4 | 0 | 24 | 3 | 0 | 4870 | 0 | 2 | 3 | 2 | 0 | ... | 3 | 53 | 2 | 2 | 2 | 2 | 2 | 0 | 0 | 2 |
5 rows × 21 columns
И перейдем к numpy.
n = data.shape[0]
n
1000
X = np.append(data.iloc[:, :-1].values.astype(float), np.ones((n, 1)), axis=1)
y = data.iloc[:, -1].values.astype(float)
X.shape, y.shape
((1000, 21), (1000,))
Найдем ранг матрицы объект-признак:
np.linalg.matrix_rank(X)
21
(повезло: признаки не являются линейно зависимыми)
Попробуем понять есть ли в данных линейные зависимости: возьмем 21 случайную строку (чтобы матрица стала квадратной) и найдем ее ранг:
np.random.seed(42)
rows = np.random.randint(1000,size=21)
nm = X[rows,:]
nm.shape, np.linalg.matrix_rank(nm)
((21, 21), 20)
Убедимся что в новой матрице нет одинаковых строк:
np.array([np.array(x) for x in set(tuple(x) for x in nm)]).shape
(21, 21)
Что следует из того что есть линейная зависимость? Попробуем решить систему линейных уравнений:
x = np.linalg.solve(X[rows], y[rows])
--------------------------------------------------------------------------- LinAlgError Traceback (most recent call last) <ipython-input-16-2c8bbe897b02> in <module>() ----> 1 x = np.linalg.solve(X[rows], y[rows]) /usr/local/lib/python2.7/site-packages/numpy/linalg/linalg.pyc in solve(a, b) 382 signature = 'DD->D' if isComplexType(t) else 'dd->d' 383 extobj = get_linalg_error_extobj(_raise_linalgerror_singular) --> 384 r = gufunc(a, b, signature=signature, extobj=extobj) 385 386 return wrap(r.astype(result_t, copy=False)) /usr/local/lib/python2.7/site-packages/numpy/linalg/linalg.pyc in _raise_linalgerror_singular(err, flag) 88 89 def _raise_linalgerror_singular(err, flag): ---> 90 raise LinAlgError("Singular matrix") 91 92 def _raise_linalgerror_nonposdef(err, flag): LinAlgError: Singular matrix
Данная система не имеет решений =(
Но не всегда так не везет!
np.random.seed(142)
rows = np.random.randint(1000,size=21)
nm = X[rows,:]
nm.shape, np.linalg.matrix_rank(nm)
((21, 21), 21)
x = np.linalg.solve(X[rows], y[rows])
x
array([ -2.99216921e-02, 8.66409086e-03, -2.25136409e-01, 7.47890269e-02, -1.30339676e-05, -2.04741197e-01, 8.28007712e-02, 8.03605876e-02, -4.09370486e-01, -2.65860629e-01, 1.71389781e-02, -6.91278040e-02, -1.03222035e-02, 2.06218175e-01, 1.99075635e-01, 5.07476369e-01, 1.96957240e-02, 1.20145042e+00, 1.79877359e-01, 4.88324529e-01, -5.48225946e-01])
Лирическое отступление: какой из признаков имеет наибольший вес?
data.columns[np.argmax(x)]
'Number of people being liable to provide maintenance for'
Но как-то скучно решать системы, где количество строк равно количеству столбцов (получается, нужно выкинуть оочень много данных). Об этом — в следующий раз!
Норма — обобщенное понятие длины вектора
Евклидова: $L_2$
$\left\lVert x \right\rVert_2 = \sqrt{\sum_{i=1}^n |x_i|^2}$
Манхеттенская: $L_1$
$\left\lVert x \right\rVert_1 = \sum_{i=1}^n |x_i|$
Минковского: $L_p$
$\left\lVert x \right\rVert_p = (\sum_{i=1}^n |x_i|^p)^{1/p}$
$L_{\infty}$:
$\left\lVert x \right\rVert_{\infty} = max_i |x_i|$
a = np.ones(n) + 1e-3 * np.random.randn(n)
print(np.linalg.norm(a, 1))
print(np.linalg.norm(a, 2))
print(np.linalg.norm(a, np.inf))
1000.01181277 31.6231647064 1.00267597135
Единичный шар — это множество точек таких что $\left\lVert x \right\rVert \le 1$. Для $L_2$ это круг, для остальных "шар" может выглядеть неожиданно:
%pylab inline
import matplotlib.pyplot as plt
def plot_disk(p):
fig = plt.figure()
M = 40000
a = np.random.randn(M, 2)
b = []
for i in xrange(M):
if np.linalg.norm(a[i, :], p) <= 1:
b.append(a[i, :])
b = np.array(b)
plt.fill(b[:, 0], b[:, 1])
plt.axis('equal')
plt.grid()
plt.show()
Populating the interactive namespace from numpy and matplotlib
plot_disk(1)
plot_disk(2)
plot_disk(np.inf)