We will use this dataset SOCR.
The dataset contains 25,000 records of human heights and weights. These data were obtained in 1993 by a Growth Survey of 25,000 children from birth to 18 years of age recruited from Maternal and Child Health Centres (MCHC) and schools.
[1]. Если у Вас не установлена библиотека Seaborn - выполните в терминале команду conda install seaborn. (Seaborn не входит в сборку Anaconda, но эта библиотека предоставляет удобную высокоуровневую функциональность для визуализации данных).
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
Считаем данные по росту и весу (weights_heights.csv, приложенный в задании) в объект Pandas DataFrame:
data = pd.read_csv('weights_heights.csv', index_col='Index')
Построим гистограмму распределения роста подростков из выборки data. Используем метод plot для DataFrame data c аргументами y='Height' (это тот признак, распределение которого мы строим)
data.plot(y='Height', kind='hist',
color='red', title='Height (inch.) distribution')
<matplotlib.axes._subplots.AxesSubplot at 0x11917e9e8>
Аргументы:
- y='Height' - тот признак, распределение которого мы строим
- kind='hist' - означает, что строится гистограмма
- color='red' - цвет
[2]. Посмотрите на первые 5 записей с помощью метода head Pandas DataFrame. Нарисуйте гистограмму распределения веса с помощью метода plot Pandas DataFrame. Сделайте гистограмму зеленой, подпишите картинку.
# Ваш код здесь
data.head(5)
Height | Weight | |
---|---|---|
Index | ||
1 | 65.78331 | 112.9925 |
2 | 71.51521 | 136.4873 |
3 | 69.39874 | 153.0269 |
4 | 68.21660 | 142.3354 |
5 | 67.78781 | 144.2971 |
data.plot(y='Weight', kind='hist',
color='green', title='Weight (f.) distribution')
<matplotlib.axes._subplots.AxesSubplot at 0x11b57def0>
Один из эффективных методов первичного анализа данных - отображение попарных зависимостей признаков. Создается
Чтобы проиллюстрировать этот метод, интересней добавить третий признак. Создадим признак Индекс массы тела (BMI). Для этого воспользуемся удобной связкой метода apply Pandas DataFrame и lambda-функций Python.
def make_bmi(height_inch, weight_pound):
METER_TO_INCH, KILO_TO_POUND = 39.37, 2.20462
return (weight_pound / KILO_TO_POUND) / \
(height_inch / METER_TO_INCH) ** 2
data['BMI'] = data.apply(lambda row: make_bmi(row['Height'],
row['Weight']), axis=1)
[3]. Постройте картинку, на которой будут отображены попарные зависимости признаков , 'Height', 'Weight' и 'BMI' друг от друга. Используйте метод pairplot библиотеки Seaborn.
sns.pairplot(data)
<seaborn.axisgrid.PairGrid at 0x11c089d30>
Часто при первичном анализе данных надо исследовать зависимость какого-то количественного признака от категориального (скажем, зарплаты от пола сотрудника). В этом помогут "ящики с усами" - boxplots библиотеки Seaborn. Box plot - это компактный способ показать статистики вещественного признака (среднее и квартили) по разным значениям категориального признака. Также помогает отслеживать "выбросы" - наблюдения, в которых значение данного вещественного признака сильно отличается от других.
[4]. Создайте в DataFrame data новый признак weight_category, который будет иметь 3 значения: 1 – если вес меньше 120 фунтов. (~ 54 кг.), 3 - если вес больше или равен 150 фунтов (~68 кг.), 2 – в остальных случаях. Постройте «ящик с усами» (boxplot), демонстрирующий зависимость роста от весовой категории. Используйте метод boxplot библиотеки Seaborn и метод apply Pandas DataFrame.
# Ваш код здесь
def weight_category(weight):
pass
# Ваш код здесь
if weight<120:
return 1
elif weight >=150:
return 3
else:
return 2
data['weight_cat'] = data['Weight'].apply(weight_category)
#sns.boxplot(data=data, x="weight_cat", y="Height").set(xlabel = u"Весовая категория", ylabel = u"Рост")
sns.boxplot(data=data, x='weight_cat' , y= 'Height')
[<matplotlib.text.Text at 0x11cf319b0>, <matplotlib.text.Text at 0x11cd5f5c0>]
[5]. Постройте scatter plot зависимости роста от веса, используя метод plot для Pandas DataFrame с аргументом kind='scatter'. Подпишите картинку.
# Ваш код здесь
data.plot(y='Height',x='Weight', kind='scatter',
color='blue', title='Height (Weight) depending')
<matplotlib.axes._subplots.AxesSubplot at 0x11cf01b70>
В простейшей постановке задача прогноза значения вещественного признака по прочим признакам (задача восстановления регрессии) решается минимизацией квадратичной функции ошибки.
[6]. Напишите функцию, которая по двум параметрам
Итак, мы решаем задачу: как через облако точек, соответсвующих наблюдениям в нашем наборе данных, в пространстве признаков "Рост" и "Вес" провести прямую линию так, чтобы минимизировать функционал из п. 6. Для начала давайте отобразим хоть какие-то прямые и убедимся, что они плохо передают зависимость роста от веса.
[7]. Проведите на графике из п. 5 Задания 1 две прямые, соответствующие значениям параметров (
def error(w0, w1):
s=0.
x=data['Weight']
y=data['Height']
for i in range(1,len(data.index)):
s+=(y[i]-w0-w1*x[i])**2
return s
x=np.array(data['Weight'])
w0,w1=60,0.05
y1 = [w0+t*w1 for t in x]
w0,w1=50,0.16
y2 = [w0+t*w1 for t in x]
data.plot(y='Height',x='Weight', kind='scatter',
color='blue', title='Height (Weight) depending')
plt.plot(x, y1, color="red", label="line1")
plt.plot(x, y2, color="green", label="line2")
plt.grid(True)
plt.legend(loc='upper left')
<matplotlib.legend.Legend at 0x11dec42b0>
Минимизация квадратичной функции ошибки - относительная простая задача, поскольку функция выпуклая. Для такой задачи существует много методов оптимизации. Посмотрим, как функция ошибки зависит от одного параметра (наклон прямой), если второй параметр (свободный член) зафиксировать.
[8]. Постройте график зависимости функции ошибки, посчитанной в п. 6, от параметра
# Ваш код здесь
w0=50.
w = np.arange(-0.5, 0.8, 0.1)
err = [error(w0,w1) for w1 in w]
plt.title('Error')
plt.xlabel('w1 ')
plt.ylabel('error(50,w1)')
plt.plot(w, err, color="red", label="function of error")
plt.legend()
<matplotlib.legend.Legend at 0x11d71b940>
Теперь методом оптимизации найдем "оптимальный" наклон прямой, приближающей зависимость роста от веса, при фиксированном коэффициенте
[9]. С помощью метода minimize_scalar из scipy.optimize найдите минимум функции, определенной в п. 6, для значений параметра
import scipy
from scipy.optimize import minimize_scalar
def error50(w1):
return error(50,w1)
min=minimize_scalar(error50, bounds=(-5,5), method='bounded')
w1_opt=min.x
min.x, min.fun
(0.14109165115062905, 79510.632440047964)
x=np.array(data['Weight'])
w0,w1=50,w1_opt
y = [w0+t*w1 for t in x]
#xx = np.linspace(np.min(data['Weight']),np.max(data['Weight']),data.count)
data.plot(y='Height',x='Weight', kind='scatter',
color='blue', title='Height (Weight) depending')
plt.plot(x, y, color="red", label="lineOptimum")
plt.grid(True)
plt.legend(loc='upper left')
<matplotlib.legend.Legend at 0x11de4aa20>
from mpl_toolkits.mplot3d import Axes3D
Создаем объекты типа matplotlib.figure.Figure (рисунок) и matplotlib.axes._subplots.Axes3DSubplot (ось).
[10]. Постройте 3D-график зависимости функции ошибки, посчитанной в п.6 от параметров
fig = plt.figure()
ax = fig.gca(projection='3d') # get current axis
w0 = np.arange(-5, 5, 0.25)
w1 = np.arange(-5, 5, 0.25)
W0, W1 = np.meshgrid(w0, w1)
E = error(W0,W1)
# используем метод *plot_surface* объекта
# типа Axes3DSubplot. Также подписываем оси.
surf = ax.plot_surface(W0, W1, E)
ax.set_xlabel('Intercept')
ax.set_ylabel('Slope')
ax.set_zlabel('Error')
plt.show()
[11]. С помощью метода minimize из scipy.optimize найдите минимум функции, определенной в п. 6, для значений параметра
def error1(w):
s=0.
x=data['Weight']
y=data['Height']
for i in range(1,len(data.index)):
s+=(y[i]-w[0]-w[1]*x[i])**2
return s
import scipy.optimize as optimize
min = optimize.minimize(error1, np.array([0,0]), method = 'L-BFGS-B', bounds=((-100,100),(-5, 5)))
min.x, min.fun
(array([ 57.57161437, 0.08200743]), 67544.152054243299)
# Ваш код здесь
x=np.array(data['Weight'])
w0,w1=min.x
y = [w0+t*w1 for t in x]
data.plot(y='Height',x='Weight', kind='scatter',
color='blue', title='Height (Weight) depending')
plt.plot(x, y, color="red", label="lineOptimum")
plt.grid(True)
plt.legend(loc='upper left')
<matplotlib.legend.Legend at 0x11da26a20>