Майнор по Анализу Данных, Группа ИАД-2

Введение, вспоминаем Python 18/01/2017

Этот Jupyter Notebook содержит вспомогательные указания для выполнения семинарских и домашних заданий. В течение курса мы будем преимущественно работать в подобных "тетрадках", но может быть иногда будем переключаться на другие среды\средства.

(Я использую Python версии 2.x.x, а не 3.x.x)

Как установить Jupyter Notebook у себя дома?!

Самый простой и надежный способ - воспользоваться готовым дистрибутивом Anaconda, включающий в себе практически все необходимые модули и утилиты, которые нам понадобятся - IPython, NumPy, SciPy, Matplotlib и Scikit-Learn. Просто следуйте указаниям установщика для вашей ОС.

Рекомендую ознакомиться с этим постом - там приводятся различные интересные возможности "тетрадок" о которых вы возможно не знали.

Можно ли писать на Python 3?

Пишите, ради бога. В нашем случае разница будет минимальна, поэтому код можно легко перевести из одной версии в другую.

Зачем мне нужен этот курс?

Данный курс должен дать вам:

  • Основные знания и навыки используемые при работе с данными
  • Понимание базовых методов прикладной статистики и (о боже!) машинного обучения
  • Умение поставить задачу и выбрать метод для ее решения

Я стану Data Scientist'ом?!

Фундамент будет заложен. А дальше нужна практика и ваша собственная мотивация.

Что желательно уметь делать, будучи DS:

  1. Data Exploration and Preparation
  2. Data Representation and Transformation
    1. Modern Databases
    2. Mathematical Representations
  3. Computing with Data
  4. Data Visualization and Presentation
  5. Data Modeling
    1. Generative Modelling (Applied Statistics)
    2. Predictive Modelling (ML)
  6. Domain Expertise (optional)

Вспоминаем pandas

In [1]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

%matplotlib inline

plt.style.use('ggplot')
plt.rcParams['figure.figsize'] = (16,8)

Рождаемость в США

Загрузите два набора данных с информацией о рождаемости в США: Набор 1, Набор 2

In [2]:
!ls 
US_births_1994-2003_CDC_NCHS.csv seminar3.ipynb
US_births_2000-2014_SSA.csv      setting_envrmt_old.ipynb
Untitled.ipynb                   sol
da_with_matrices.ipynb           sol~
hw1_old.ipynb                    temp.txt
intro.ipynb                      tutorial_dataset.csv
seminar1_lns_old.ipynb           tutorial_dataset_2.csv
seminar2.ipynb
In [3]:
df1 = pd.read_csv('US_births_1994-2003_CDC_NCHS.csv')
df2 = pd.read_csv('US_births_2000-2014_SSA.csv')
In [6]:
df1.tail()
Out[6]:
year month date_of_month day_of_week births
3647 2003 12 27 6 8646
3648 2003 12 28 7 7645
3649 2003 12 29 1 12823
3650 2003 12 30 2 14438
3651 2003 12 31 3 12374
In [5]:
df2.head()
Out[5]:
year month date_of_month day_of_week births
0 2000 1 1 6 9083
1 2000 1 2 7 8006
2 2000 1 3 1 11363
3 2000 1 4 2 13032
4 2000 1 5 3 12558

Чем они отличаются? Соедините 2 таблицы, так, чтобы соблюсти целостность информации.

In [7]:
# 1) Проверьте, что данные за общий период почти 
# не отличаются
# 2) Объедините таблицы, чтобы они охватывали период 
# 1994-2014
In [9]:
df1 = df1.rename(columns={'date_of_month': 'day'})
In [11]:
df1.loc[:, 'date'] = \
pd.to_datetime(df1.loc[:, ['year', 'month', 'day']])
df1.head()
Out[11]:
year month day day_of_week births date
0 1994 1 1 6 8096 1994-01-01
1 1994 1 2 7 7772 1994-01-02
2 1994 1 3 1 10142 1994-01-03
3 1994 1 4 2 11248 1994-01-04
4 1994 1 5 3 11053 1994-01-05
In [19]:
df2 = df2.rename(columns={'date_of_month': 'day'})
df2.loc[:, 'date'] = \
pd.to_datetime(df2.loc[:, ['year', 'month', 'day']])
df2.head()
Out[19]:
year month day day_of_week births date
0 2000 1 1 6 9083 2000-01-01
1 2000 1 2 7 8006 2000-01-02
2 2000 1 3 1 11363 2000-01-03
3 2000 1 4 2 13032 2000-01-04
4 2000 1 5 3 12558 2000-01-05
In [22]:
df1 = df1.set_index('date')
df2 = df2.set_index('date')
In [27]:
df1.head()
Out[27]:
year month day day_of_week births
date
1994-01-01 1994 1 1 6 8096
1994-01-02 1994 1 2 7 7772
1994-01-03 1994 1 3 1 10142
1994-01-04 1994 1 4 2 11248
1994-01-05 1994 1 5 3 11053
In [28]:
df2.head()
Out[28]:
year month day day_of_week births
date
2000-01-01 2000 1 1 6 9083
2000-01-02 2000 1 2 7 8006
2000-01-03 2000 1 3 1 11363
2000-01-04 2000 1 4 2 13032
2000-01-05 2000 1 5 3 12558
In [30]:
result = df1.join(df2, how='inner', 
                  lsuffix='_df1', rsuffix='_df2')
In [37]:
result.tail()
Out[37]:
year_df1 month_df1 day_df1 day_of_week_df1 births_df1 year_df2 month_df2 day_df2 day_of_week_df2 births_df2
date
2003-12-27 2003 12 27 6 8646 2003 12 27 6 8785
2003-12-28 2003 12 28 7 7645 2003 12 28 7 7763
2003-12-29 2003 12 29 1 12823 2003 12 29 1 13125
2003-12-30 2003 12 30 2 14438 2003 12 30 2 14700
2003-12-31 2003 12 31 3 12374 2003 12 31 3 12540
In [35]:
# Сравним рождаемости
result.loc[:, ['births_df1', 'births_df2']]
(result.births_df1 - result.births_df2).mean()
Out[35]:
-223.48459958932239
In [36]:
(result.births_df1 - result.births_df2).describe()
Out[36]:
count    1461.000000
mean     -223.484600
std        68.774771
min      -438.000000
25%      -271.000000
50%      -231.000000
75%      -170.000000
max       -60.000000
dtype: float64
In [38]:
df3 = df1.append(df2.loc['2004-01-01':, :])
In [41]:
# Проверим, что даты не повторяются
df3.index.value_counts().head()
# Даты уникальны!
Out[41]:
2007-09-10    1
2000-09-26    1
2000-09-28    1
1997-12-03    1
1996-08-22    1
2005-09-22    1
2009-11-14    1
2002-06-28    1
2003-01-25    1
1995-10-11    1
1999-03-15    1
2001-06-26    1
2004-11-28    1
2008-05-02    1
1998-07-02    1
2005-12-17    1
2003-06-29    1
1997-05-14    1
1998-12-04    1
2009-12-01    1
2013-11-21    1
2007-08-20    1
2000-01-08    1
2014-07-28    1
1995-06-15    1
2014-12-25    1
2009-04-28    1
1995-05-06    1
1996-07-24    1
2014-06-26    1
             ..
1998-01-03    1
1994-08-01    1
2000-10-01    1
2005-07-24    1
2007-11-01    1
1997-08-30    1
1998-09-13    1
1996-10-30    1
2003-11-06    1
1994-07-19    1
1995-01-06    1
1998-06-10    1
2001-11-12    1
2004-02-24    1
2007-07-29    1
2008-09-18    1
2012-02-21    1
1996-06-05    1
1994-02-18    1
2010-09-12    1
2013-08-15    1
2006-10-18    1
2001-05-25    1
2011-05-13    1
2014-04-27    1
2012-10-24    1
2003-08-30    1
2009-11-21    1
2008-03-31    1
2006-03-22    1
Name: date, dtype: int64

Найдите количество детей, рождающихся 6, 13 и 20 числа каждого месяца с учетом дня недели.

Выделяется ли как-то пятница 13?

In [51]:
# Сделаем таблицу для 6 числа
idx = df3.loc[:, 'day'] == 6
b6 = df3.loc[idx, :].groupby('day_of_week').births.mean()

# И для всех остальных
idx = df3.loc[:, 'day'] == 13
b13 = df3.loc[idx, :].groupby('day_of_week').births.mean()

idx = df3.loc[:, 'day'] == 20
b20 = df3.loc[idx, :].groupby('day_of_week').births.mean()
In [52]:
b6-b20
Out[52]:
day_of_week
1   -597.400000
2   -448.805556
3    -79.028571
4   -167.131579
5   -237.342857
6    -71.361111
7    -19.189189
Name: births, dtype: float64
In [56]:
b20-b13
Out[56]:
day_of_week
1    520.142857
2    491.722222
3    403.742857
4    507.052632
5    911.342857
6     93.805556
7     81.891892
Name: births, dtype: float64

Качество вина

Загрузите датасет с информацией о характеристиках вина и его качестве.

In [ ]:
 
  • Что из себя представляет объект в этом наборе данных? Сколько их?
  • Какие признаки описывают объекты? Сколько их?
  • Какой признак является целевым?
  • Каковы их области значений?
  • Есть ли пропуски?
In [ ]:
 

Какие признаки больше всего влияют на целевую переменную?

In [ ]:
 

Создайте новый столбец quality_cat, которая будет иметь значение "good" если quality > 5 и "bad" - иначе.

In [ ]:
 

Нарисуйте гистрограммы признака alcohol в группах с quality_cat == "good" и quality_cat == "bad".

In [ ]:
 

Можете ли вы придумать правило для классификации вина на хорошее и плохое по рисунку выше? Пусть это будет нашей первой моделью)

Напишите функцию brute_clf_train() которая бы перебирала пороговое значение по признаку alcohol и находило бы "оптимальное" (кстати, что значит оптимальное?)

In [ ]:
 

Напишите функцию brute_clf_predict() которая бы по значению признака alcohol и найденному выше порогу говорила какое качество у вина.

А заодно выводила бы количество "ошибок" на текущем наборе данных

Проверим, как обобщается наша модель на другие данные.

  • Загрузите другой датасет
  • Выполните те же панипуляции с признаками
  • Используйте нашу простейшую модель для предсказания качества на новых данных
In [ ]:
 

Вспоминаем NumPy

Упражнения с векторами и матрицами

In [ ]:
 

Линейная регрессия

Загрузите файл 1 и файл 2 в папку с тетрадкой. С помощью функции loadtxt в модуле numpy загрузите табличные данные одного из файлов. Присвойте y = D[:,0] а X = D[:, 1:].

Сейчас мы воспользуемся одной магической формулой и построим модель линейной регрессии. Откуда эта формула берется мы узнаем на следующих занятиях.

Модель линейной регрессии в матричном виде выглядит так: $\hat{y} = X\hat{\beta}$, где

$$ \hat{\beta} = (X^T X)^{-1} X^T y $$

Остатки модели рассчитываются как $$ \text{res} = y - \hat{y} $$

Итак, еще раз:

  1. Загрузите данные
  2. Оцените веса $\beta$ с помощью формулы
  3. Постройте график, на котором по оси Y: остатки, а по оси X: $\hat{y}$
In [ ]:
# load data
D = np.loadtxt('tutorial_dataset_1.csv', 
               skiprows=1, 
               delimiter=',')
In [ ]:
# Write your code here
#
#
#