├── .gitattributes ├── .gitignore ├── _config.yml ├── data ├── telecom_churn.py ├── Открытый курс машинного обучения. Тема 2. Визуализация данных c Python.py └── Прогноз популярности статьи на Хабре.py ├── Анализ текстов.py ├── Задание по программированию Выбор метрики Бостон.py ├── Неделя 3, Логистическая регрессия.py ├── Неделя 3. Метрики качества классификации.py ├── Неделя 4. Линейная регрессия - прогноз оклада по описанию вакансии.py ├── Неделя 4. Составление фондового индекса.py ├── Неделя 5. Градиентный бустинг над решающими деревьями.py ├── Неделя 5. Размер случайного леса.py ├── Нормализация признаков Перцептрон.py ├── Опорные объекты.py ├── Статистика по Титанику.py ├── Финальное задание Игра Dota 2 ├── Финальное задание final.py └── Финальное задание.py ├── Характеристики вин.py ├── бустинг имитации отжига 4.py ├── бустинг имитации отжига 5.py └── неделя 6. Уменьшение количества цветов изображения.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask instance folder 57 | instance/ 58 | 59 | # Scrapy stuff: 60 | .scrapy 61 | 62 | # Sphinx documentation 63 | docs/_build/ 64 | 65 | # PyBuilder 66 | target/ 67 | 68 | # IPython Notebook 69 | .ipynb_checkpoints 70 | 71 | # pyenv 72 | .python-version 73 | 74 | # celery beat schedule file 75 | celerybeat-schedule 76 | 77 | # dotenv 78 | .env 79 | 80 | # virtualenv 81 | venv/ 82 | ENV/ 83 | 84 | # Spyder project settings 85 | .spyderproject 86 | 87 | # Rope project settings 88 | .ropeproject 89 | 90 | # ========================= 91 | # Operating System Files 92 | # ========================= 93 | 94 | # OSX 95 | # ========================= 96 | 97 | .DS_Store 98 | .AppleDouble 99 | .LSOverride 100 | 101 | # Thumbnails 102 | ._* 103 | 104 | # Files that might appear in the root of a volume 105 | .DocumentRevisions-V100 106 | .fseventsd 107 | .Spotlight-V100 108 | .TemporaryItems 109 | .Trashes 110 | .VolumeIcon.icns 111 | 112 | # Directories potentially created on remote AFP share 113 | .AppleDB 114 | .AppleDesktop 115 | Network Trash Folder 116 | Temporary Items 117 | .apdisk 118 | 119 | # Windows 120 | # ========================= 121 | 122 | # Windows image file caches 123 | Thumbs.db 124 | ehthumbs.db 125 | 126 | # Folder config file 127 | Desktop.ini 128 | 129 | # Recycle Bin used on file shares 130 | $RECYCLE.BIN/ 131 | 132 | # Windows Installer files 133 | *.cab 134 | *.msi 135 | *.msm 136 | *.msp 137 | 138 | # Windows shortcuts 139 | *.lnk 140 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-minimal -------------------------------------------------------------------------------- /data/telecom_churn.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sat Mar 11 13:09:39 2017 4 | 5 | 6 | """ 7 | 8 | # импортируем Pandas и Numpy 9 | import pandas as pd 10 | import numpy as np 11 | import seaborn as sns 12 | import matplotlib.pyplot as plt 13 | from sklearn.manifold import TSNE 14 | from sklearn.preprocessing import StandardScaler 15 | 16 | #открываем файл с данными 17 | df = pd.read_csv('telecom_churn.csv') 18 | 19 | print('Размер датафрейма') 20 | print(df.shape) 21 | 22 | print('Колонки') 23 | print(df.columns) 24 | 25 | print('Общая информация') 26 | print(df.info()) 27 | 28 | #изменяем с булева на целый числовой 29 | df['Churn'] = df['Churn'].astype('int64') 30 | 31 | print('Основные статистические характеристики данных по каждому числовому признаку (типы int64 и float64)') 32 | print(df.describe()) 33 | 34 | #Чтобы посмотреть статистику по нечисловым признакам, нужно явно указать интересующие нас типы в параметре include. 35 | print('Статистика по нечисловым признакам') 36 | print(df.describe(include=['object', 'bool'])) 37 | 38 | print('Распределение значений целевой переменной') 39 | print(df['Churn'].value_counts()) 40 | 41 | 42 | #Посмотрим на распределение пользователей по переменной Area code. 43 | #Укажем значение параметра normalize=True, чтобы посмотреть не абсолютные частоты, а относительные. 44 | #Area code-Префикс номера телефона 45 | print('распределение по префиксу номеров телефона') 46 | print(df['Area code'].value_counts(normalize=True))#значения в процентах по частоте 47 | 48 | print('Сортировка по группе столбцов') 49 | print(df.sort_values(by=['Churn', 'Total day charge'], 50 | ascending=[True, False]).head()) 51 | 52 | #логическая выборка 53 | print('Cколько в среднем в течение дня разговаривают по телефону нелояльные пользователи?') 54 | print(df[df['Churn'] == 1]['Total day minutes'].mean()) 55 | 56 | print('Какова максимальная длина международных звонков среди лояльных пользователей (Churn == 0), не пользующихся услугой международного роуминга ("International plan" == "No")?') 57 | print(df[(df['Churn'] == 0) & (df['International plan'] == 'No')]['Total intl minutes'].max()) 58 | 59 | print('Только первая строка') 60 | print(df[:1]) 61 | 62 | print('Только последняя строка') 63 | print(df[-1:]) 64 | 65 | 66 | print('используем map для обработки каждой строки') 67 | d = {'No' : False, 'Yes' : True} 68 | df['International plan'] = df['International plan'].map(d) 69 | print(df.head()) 70 | 71 | 72 | #============================================================================== 73 | # Группировка данных 74 | # df.groupby(by=grouping_columns)[columns_to_show].function() 75 | # К датафрейму применяется метод groupby, который разделяет данные по grouping_columns – признаку или набору признаков. 76 | # Выбираем нужные нам столбцы (columns_to_show). 77 | # К полученным группам применяется функция или несколько функций. 78 | #============================================================================== 79 | 80 | #Группирование данных в зависимости от значения признака Churn и вывод статистик по трём столбцам в каждой группе. 81 | 82 | columns_to_show = ['Total day minutes', 'Total eve minutes', 'Total night minutes'] 83 | print(df.groupby(['Churn'])[columns_to_show].describe(percentiles=[])) 84 | 85 | #Сделаем то же самое, но немного по-другому, передав в agg список функций: 86 | columns_to_show = ['Total day minutes', 'Total eve minutes', 'Total night minutes'] 87 | print(df.groupby(['Churn'])[columns_to_show].agg([np.mean, np.std, np.min, np.max])) 88 | 89 | 90 | #============================================================================== 91 | #Сводные таблицы 92 | # Допустим, мы хотим посмотреть, как наблюдения в нашей выборке распределены в контексте двух признаков — Churn и International plan. 93 | # Для этого мы можем построить таблицу сопряженности, воспользовавшись методом crosstab: 94 | #============================================================================== 95 | print('Кросс таблицы в абсолютном выражении') 96 | print(pd.crosstab(df['Churn'], df['International plan'])) 97 | 98 | print('Кhосс таблицы, по процентам') 99 | print(pd.crosstab(df['Churn'], df['Voice mail plan'], normalize=True)) 100 | 101 | #В Pandas за сводные таблицы отвечает метод pivot_table, который принимает в качестве параметров: 102 | #values – список переменных, по которым требуется рассчитать нужные статистики, 103 | #index – список переменных, по которым нужно сгруппировать данные, 104 | #aggfunc — то, что нам, собственно, нужно посчитать по группам — сумму, среднее, максимум, минимум или что-то ещё. 105 | 106 | #Area code - строки 107 | #'Total day calls', 'Total eve calls', 'Total night calls' - столбцы 108 | #aggfunc='mean' - аггрегирующая функция в ячейках 109 | print('Сводные таблицы') 110 | print(df.pivot_table(['Total day calls', 'Total eve calls', 'Total night calls'], ['Area code'], aggfunc='mean').head(10)) 111 | 112 | #добавление столбца как суммы других столбцов 113 | df['Total charge'] = df['Total day charge'] + df['Total eve charge'] + df['Total night charge'] + df['Total intl charge'] 114 | 115 | #drop - удаление столбца и строк 116 | 117 | print('--- Первые попытки прогнозирования оттока ---') 118 | print('Посмотрим, как отток связан с признаком "Подключение международного роуминга" (International plan). Сделаем это с помощью сводной таблички crosstab') 119 | #margins=True - общий итог 120 | print(pd.crosstab(df['Churn'], df['International plan'], margins=True)) 121 | 122 | print('Далее посмотрим на еще один важный признак – "Число обращений в сервисный центр" (Customer service calls). Также построим сводную таблицу и картинку.') 123 | print(pd.crosstab(df['Churn'], df['Customer service calls'], margins=True)) 124 | 125 | #Добавим колонку количество звонков в техподдержку 126 | df['Many_service_calls'] = (df['Customer service calls'] > 3).astype('int')#по сути булево значение 127 | print(pd.crosstab(df['Many_service_calls'], df['Churn'], margins=True)) 128 | 129 | print('Объединенная статистика') 130 | print(pd.crosstab(df['Many_service_calls'] & df['International plan'] , df['Churn'], normalize=True)) 131 | 132 | #Доля лояльных клиентов в выборке – 85.5%. Самая наивная модель, ответ которой "клиент всегда лоялен" 133 | #на подобных данных будет угадывать примерно в 85.5% случаев. 134 | #То есть доли правильных ответов (accuracy) последующих моделей должны быть как минимум не меньше, а лучше, значительно выше этой цифры; 135 | print('Доля лояльных клиентов в выборке') 136 | print(round(df['Churn'].value_counts(normalize=True)[0]*100,2)) 137 | 138 | #С помощью простого прогноза, который условно можно выразить такой формулой: 139 | #"International plan = False & Customer Service calls < 4 => Churn = 0, else Churn = 1", 140 | #можно ожидать долю угадываний 85.8%, что еще чуть выше 85.5%. 141 | #Впоследствии мы поговорим о деревьях решений и разберемся, как находить подобные правила автоматически на основе только 142 | #входных данных; 143 | 144 | #Перед обучением сложных моделей рекомендуется немного покрутить данные и 145 | #проверить простые предположения. Более того, в бизнес-приложениях машинного обучения чаще 146 | #всего начинают именно с простых решений, а потом экспериментируют с их усложнениями. 147 | 148 | 149 | #Посмотрим на распределение целевого класса – оттока клиентов. 150 | #plt=df['Churn'].value_counts().plot(kind='bar', label='Churn',title='Распределение оттока клиентов',legend = True) 151 | 152 | #Выделим следующие группы признаков (среди всех кроме Churn ): 153 | #1. бинарные: International plan, Voice mail plan 154 | #2. категориальные: State 155 | #3. порядковые: Customer service calls 156 | #5. количественные: все остальные 157 | # 158 | #Посмотрим на корреляции количественных признаков. По раскрашенной матрице корреляций видно, 159 | #что такие признаки как Total day charge считаются по проговоренным минутам (Total day minutes). 160 | #То есть 4 признака можно выкинуть, они не несут полезной информации. 161 | 162 | corr_matrix = df.drop(['State', 'International plan', 'Voice mail plan', 163 | 'Area code'], axis=1).corr() 164 | #sns.heatmap(corr_matrix); 165 | #print(corr_matrix.index) 166 | 167 | #линейно зависимые признаки 168 | #Total day minutes - Total day charge 169 | #Total eve minutes - Total eve charge 170 | #Total night minutes - Total night charge 171 | #Total intl minutes - Total intl charge 172 | 173 | 174 | #Теперь посмотрим на распределения всех интересующих нас количественных признаков. 175 | #выкидываем ненужные колонки 176 | features = df.drop(['State', 'International plan', 'Voice mail plan', 'Area code', 177 | 'Total day charge', 'Total eve charge', 'Total night charge', 178 | 'Total intl charge', 'Churn'],axis=1) 179 | 180 | #features.hist(figsize=(20,12)) 181 | 182 | 183 | #Видим, что большинство признаков распределены нормально. 184 | #Исключения – число звонков в сервисный центр (Customer service calls) 185 | #(тут больше подходит пуассоновское распределение) и 186 | #число голосовых сообщений (Number vmail messages, пик в нуле, т.е. это те, 187 | #у кого голосовая почта не подключена). Также смещено распределение числа международных звонков (Total intl calls). 188 | 189 | #Еще полезно строить вот такие картинки, где на главной диагонали рисуются распредления признаков, 190 | #а вне главной диагонали – диаграммы рассеяния для пар признаков. Бывает, что это приводит к каким-то выводам, 191 | #но в данном случае все примерно понятно, без сюрпризов. 192 | featuresList = list(set(df.columns) - set(['State', 'International plan', 'Voice mail plan', 'Area code', 193 | 'Total day charge', 'Total eve charge', 'Total night charge', 194 | 'Total intl charge','Churn'])) 195 | 196 | #df[features].hist(figsize=(20,12)) 197 | #sns.pairplot(df[featuresList + ['Churn']], hue='Churn') 198 | 199 | #Построим boxplot-ы, описывающее статистики распределения количественных признаков в двух группах: 200 | #среди лояльных и ушедших клиентов. 201 | 202 | #fig, axes = plt.subplots(nrows=3, ncols=4, figsize=(16, 10)) 203 | 204 | #for idx, feat in enumerate(features): 205 | #sns.boxplot(x='Churn', y=feat, data=df, ax=axes[idx / 4, idx % 4]) 206 | #axes[idx / 4, idx % 4].legend() 207 | #axes[idx / 4, idx % 4].set_xlabel('Churn') 208 | #axes[idx / 4, idx % 4].set_ylabel(feat); 209 | 210 | 211 | #На глаз наибольшее отличие мы видим для признаков Total day minutes, Customer service calls и Number vmail messages. 212 | 213 | #_, axes = plt.subplots(1, 2, sharey=True, figsize=(16,6)) 214 | 215 | #sns.boxplot(x='Churn', y='Total day minutes', data=df, ax=axes[0]); 216 | #sns.violinplot(x='Churn', y='Total day minutes', data=df, ax=axes[1]); 217 | 218 | #Интересное наблюдение: в среднем ушедшие клиенты больше пользуются связью. 219 | #Возможно, они недовольны тарифами, и одной из мер борьбы с оттоком будет понижение тарифных ставок 220 | #(стоимости мобильной связи). 221 | #Но это уже компании надо будет проводить дополнительный экономический анализ, 222 | #действительно ли такие меры будут оправданы. 223 | 224 | #Теперь изобразим распределение числа обращений в сервисный центр. 225 | #Тут уникальных значений признака не много (признак можно считать как количественным целочисленным, 226 | #так и порядковым), и наглядней изобразить распределение с помощью countplot. 227 | #Наблюдение: доля оттока сильно возрастает начиная с 4 звонков в сервисный центр. 228 | 229 | #sns.countplot(x='Customer service calls', hue='Churn', data=df) 230 | 231 | #Теперь посмотрим на связь бинарных признаков International plan и Voice mail plan с оттоком. 232 | #Наблюдение: когда роуминг подключен, доля оттока намного выше, 233 | #т.е. наличие международного роуминга – сильный признак. Про голосовую почту такого нельзя сказать. 234 | 235 | #_, axes = plt.subplots(1, 2, sharey=True, figsize=(16,6)) 236 | 237 | #sns.countplot(x='International plan', hue='Churn', data=df, ax=axes[0]); 238 | #sns.countplot(x='Voice mail plan', hue='Churn', data=df, ax=axes[1]); 239 | 240 | #Наконец, посмотрим, как с оттоком связан категориальный признак State. 241 | #С ним уже не так приятно работать, поскольку число уникальных штатов довольно велико – 51. 242 | #Можно в начале построить сводную табличку или посчитать процент оттока для каждого штата. 243 | #Но данных по каждом штату по отдельности маловато (ушедших клиентов всего от 3 до 17 в каждом штате), 244 | #поэтому, возможно, признак State впоследствии не стоит добавлять в модели классификации из-за риска 245 | # переобучения (но мы это будем проверять на кросс-валидации, stay tuned!). 246 | #Доли оттока для каждого штата: 247 | 248 | print('Штаты с большим оттоком') 249 | StateChurn=df.groupby(['State'])['Churn'].agg([np.mean]).sort_values(by='mean', ascending=False) 250 | print(StateChurn.head(10)) 251 | 252 | # преобразуем все признаки в числовые, выкинув штаты 253 | X = df.drop(['Churn', 'State'], axis=1) 254 | X['International plan'] = pd.factorize(X['International plan'])[0] 255 | X['Voice mail plan'] = pd.factorize(X['Voice mail plan'])[0] 256 | 257 | scaler = StandardScaler() 258 | X_scaled = scaler.fit_transform(X) 259 | 260 | 261 | tsne = TSNE(random_state=17) 262 | tsne_representation = tsne.fit_transform(X_scaled) 263 | 264 | #plt.scatter(tsne_representation[:, 0], tsne_representation[:, 1], 265 | #c=df['Churn'].map({0: 'green', 1: 'red'})); 266 | 267 | _, axes = plt.subplots(1, 2, sharey=True, figsize=(16,6)) 268 | 269 | axes[0].scatter(tsne_representation[:, 0], tsne_representation[:, 1], 270 | c=df['International plan'].map({'Yes': 'green', 'No': 'red'})) 271 | axes[1].scatter(tsne_representation[:, 0], tsne_representation[:, 1], 272 | c=df['Voice mail plan'].map({'Yes': 'green', 'No': 'red'})) 273 | 274 | axes[0].set_title('International plan') 275 | axes[1].set_title('Voice mail plan') -------------------------------------------------------------------------------- /data/Открытый курс машинного обучения. Тема 2. Визуализация данных c Python.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sat Mar 11 18:49:59 2017 4 | 5 | 6 | """ 7 | 8 | #увеличим дефолтный размер графиков 9 | from pylab import rcParams 10 | rcParams['figure.figsize'] = 15, 7 11 | import pandas as pd 12 | import seaborn as sns 13 | 14 | 15 | df = pd.read_csv('video_games_sales.csv') 16 | #df.info() 17 | 18 | #============================================================================== 19 | # Данные об оценках есть не для всех фильмов, поэтому давайте оставим только те записи, 20 | # в которых нет пропусков с помощью метода dropna. 21 | #============================================================================== 22 | 23 | df = df.dropna() 24 | df['User_Score'] = df['User_Score'].astype('float64') 25 | 26 | #Для примера построим график продаж видео игр в различных странах в зависимости от года. 27 | #Для начала отфильтруем только нужные нам столбцы, затем посчитаем суммарные продажи по годам и у получившегося 28 | #dataframe вызовем функцию plot без параметров. 29 | 30 | sales_df = df[[x for x in df.columns if 'Sales' in x] + ['Year_of_Release']]#создается массив колонок с перебором по вхождению названия и добавляется еще колонка 31 | #sales_df.groupby('Year_of_Release').sum().plot()#стандартный график 32 | 33 | #Например, параметра rot отвечает за угол наклона подписей к оси x. 34 | #sales_df.groupby('Year_of_Release').sum().plot(kind='bar', rot=45)#столбчатая диаграмма 35 | 36 | #Познакомимся с первым таким "сложным" типом графиков pair plot (scatter plot matrix). 37 | #Эта визуализация поможет нам посмотреть на одной картинке, как связаны между собой различные признаки. 38 | cols = ['Global_Sales', 'Critic_Score', 'Critic_Count', 'User_Score', 'User_Count'] 39 | #sns_plot = sns.pairplot(df[cols]) 40 | #sns_plot.savefig('pairplot.png') 41 | 42 | #посмотрим на распределение оценок критиков Critic_Score. 43 | #По умолчанию на графике отображается гистограмма и kernel density estimation. 44 | #sns.distplot(df.Critic_Score) 45 | 46 | #Для того, чтобы подробнее посмотреть на взаимосвязь двух численных признаков, 47 | #есть еще и joint plot — это гибрид scatter plot и histogram. Посмотрим на то, 48 | #как связаны между собой оценка критиков Critic_Score и оценка пользователя User_Score. 49 | #sns.jointplot(df.Critic_Score,df.User_Score) 50 | 51 | #============================================================================== 52 | # #Еще один полезный тип графиков — это box plot. 53 | # #Давайте сравним оценки игр от критиков для топ-5 крупнейших игровых платформ. 54 | #============================================================================== 55 | #Думаю, стоит обсудить немного подробнее, как же понимать box plot. 56 | #Box plot состоит из коробки (поэтому он и называется box plot), усиков и точек. 57 | #Коробка показывает интерквартильный размах распределения, то есть соответственно 25% (Q1) и 75% (Q3) перцентили. 58 | #Черта внутри коробки обозначает медиану распределения. 59 | #С коробкой разобрались, перейдем к усам. Усы отображают весь разброс точек кроме выбросов, 60 | #то есть минимальные и максимальные значения, которые попадают в промежуток 61 | #(Q1 - 1.5*IQR, Q3 + 1.5*IQR), где IQR = Q3 - Q1 — интерквартильный размах. 62 | #Точками на графике обозначаются выбросы (outliers) — те значения, которые не вписываются в промежуток 63 | #значений, заданный усами графика. 64 | 65 | #top_platforms = df.Platform.value_counts().sort_values(ascending = False).head(5).index.values 66 | #sns.boxplot(y="Platform", x="Critic_Score", data=df[df.Platform.isin(top_platforms)], orient="h") 67 | 68 | 69 | #И еще один тип графиков (последний из тех, которые мы рассмотрим в этой статье) — это heat map. 70 | #Heat map позволяет посмотреть на распределение какого-то численного признака по двум категориальным. 71 | #Визуализируем суммарные продажи игр по жанрам и игровым платформам. 72 | platform_genre_sales = df.pivot_table( 73 | index='Platform', 74 | columns='Genre', 75 | values='Global_Sales', 76 | aggfunc=sum).fillna(0).applymap(float) 77 | sns.heatmap(platform_genre_sales, annot=True, fmt=".1f", linewidths=.5) -------------------------------------------------------------------------------- /data/Прогноз популярности статьи на Хабре.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sun Mar 12 13:43:34 2017 4 | 5 | 6 | """ 7 | import pandas as pd 8 | import seaborn as sns 9 | import matplotlib.pyplot as plt 10 | 11 | df = pd.read_csv('howpop_train.csv') 12 | 13 | #Избавимся сразу от переменных, названия которых заканчиваются на _lognorm (нужны для соревнования на Kaggle). Выберем их с помощью filter() и удалим drop-ом: 14 | df.drop(filter(lambda c: c.endswith('_lognorm'), df.columns), 15 | axis = 1, # axis = 1: столбцы 16 | inplace = True) # избавляет от необходимости сохранять датасет 17 | 18 | # настройка внешнего вида графиков в seaborn 19 | sns.set_style("dark") 20 | sns.set_palette("RdBu") 21 | sns.set_context("notebook", font_scale = 1.5, 22 | rc = { "figure.figsize" : (25, 5), "axes.titlesize" : 18 }) 23 | 24 | 25 | #Столбец published (время публикации) содержит строки. Чтобы мы могли работать с этими данными как с 26 | #датой/временем публикации, приведём их к типу datetime: 27 | #print(df.published.dtype) 28 | df['published'] = pd.to_datetime(df.published, yearfirst = True) 29 | #print(df.published.dtype) 30 | 31 | 32 | #Создадим несколько столбцов на основе данных о времени публикации: 33 | df['year'] = [d.year for d in df.published] 34 | df['month'] = [d.month for d in df.published] 35 | 36 | df['dayofweek'] = [d.isoweekday() for d in df.published] 37 | df['hour'] = [d.hour for d in df.published] 38 | df['dayofmonth'] = [d.day for d in df.published] 39 | 40 | 41 | #В каком месяце (и какого года) было больше всего публикаций? 42 | #dateFrame=df[(df.year>2014) & (df.month==3)].groupby(['year','month'],sort=True)['post_id'].count() 43 | 44 | dateFrame=df[df.year>2014].groupby(['year','month'],sort=True)['post_id'].count() 45 | #dateFrame.plot(kind='bar', rot=90,grid=True) 46 | dateFrame.sort_values(ascending=False, inplace=True) 47 | 48 | val=dateFrame.head(1).index.values[0]#численный максимум - берем имя индекса 49 | #print('Максимум на %d.%d' %(val[0],val[1])) 50 | 51 | del dateFrame 52 | #март 2015 53 | 54 | #Проанализируйте публикации в этом месяце (из вопроса 1), отметьте все подходящие утверждения 55 | dateFrame=df[(df.year==val[0])&(df.month==val[1])].copy()#делаем выборку за указанный период, копированием датасета 56 | #dateFrame=dateFrame.groupby('dayofweek')['post_id'].count().T 57 | #dateFrame.plot(kind='bar', rot=90,grid=True) 58 | 59 | #в субботу и воскресенье проседание - публикуют меньше всего 60 | 61 | #На хабре всегда больше статей, чем на гиктаймсе 62 | dateFrame['habr']=dateFrame.domain.map(lambda x: 1 if x.startswith('habrahabr.ru') else 0) 63 | dateFrame['geek']=dateFrame.domain.map(lambda x: 1 if x.startswith('geektimes.ru') else 0) 64 | 65 | #habrGeek=dateFrame.groupby(['dayofmonth'],sort=True)['habr','geek'].sum() 66 | #habrGeek.plot(kind='bar', rot=90,grid=True) 67 | #ответ нет, дни 14, 21 68 | 69 | 70 | #По субботам на гиктаймс и на хабрахабр публикуют примерно одинаковое число статей 71 | habrGeek=dateFrame[dateFrame.dayofweek==6].groupby(['dayofweek'],sort=True)['habr','geek'].sum() 72 | #habrGeek.plot(kind='bar', rot=90,grid=True) 73 | #ответ Да 74 | del dateFrame 75 | del habrGeek 76 | 77 | #Больше всего просмотров набирают статьи, опубликованные в 12 часов дня? 78 | dateFrame=df.groupby(['hour'],sort=True)['views'].sum() 79 | dateFrame.sort_values(ascending=False, inplace=True) 80 | #dateFrame.plot(kind='bar', rot=90,grid=True, title='Просмотры') 81 | #оттвет ДА 82 | del dateFrame 83 | 84 | #У опубликованных в 10 утра постов больше всего комментариев 85 | dateFrame=df.groupby(['hour'],sort=True)['comments'].sum() 86 | #dateFrame.plot(kind='bar', rot=90,grid=True, title='Комментарии') 87 | #ответ НЕТ, правильно в 13 часов 88 | del dateFrame 89 | 90 | #Больше всего просмотров набирают статьи, опубликованные в 6 часов утра 91 | #Ответ - НЕТ 92 | 93 | #Максимальное число комментариев на гиктаймсе набрала статья, опубликованная в 9 часов вечера 94 | dateFrame=df.copy() 95 | dateFrame['geek']=dateFrame.domain.map(lambda x: x.startswith('geektimes.ru')) 96 | 97 | select=dateFrame[dateFrame.geek==True].groupby(['hour'],sort=True)['comments'].sum() 98 | #select.plot(kind='bar', rot=90,grid=True, title='Комментарии к geektimes') 99 | #Ответ - НЕТ,пhавильный ответ 12 часов 100 | del dateFrame 101 | del select 102 | 103 | 104 | #На хабре дневные статьи комментируют чаще, чем вечерние 105 | dateFrame=df.copy() 106 | dateFrame['habr']=dateFrame.domain.map(lambda x: x.startswith('habrahabr.ru')) 107 | dateFrame['day_comments']=(dateFrame[['comments','hour']]).apply(lambda x: x.comments if (x.hour>=12)and(x.hour<18) else 0,axis =1) 108 | dateFrame['eve_comments']=(dateFrame[['comments','hour']]).apply(lambda x: x.comments if (x.hour>=18)and(x.hour<=23) else 0,axis =1) 109 | 110 | dateFrame=dateFrame[(dateFrame.habr==True)&(dateFrame.hour>=12)].groupby(['hour'],sort=True)['day_comments','eve_comments'].sum() 111 | dateFrame.plot(kind='bar', rot=45,grid=True,title='На хабре дневные статьи комментируют чаще, чем вечерние') 112 | #Ответ ДА 113 | 114 | #Кого из топ-20 авторов (по числу статей) чаще всего минусуют (в среднем) 115 | dateFrame=df.copy() 116 | dateFrame=dateFrame.groupby(['author'],sort=True)['post_id'].count() 117 | dateFrame.sort_values(ascending=False, inplace=True) 118 | topAuthor=dateFrame.head(20).index.values 119 | 120 | dateFrame=df[df.author.isin(topAuthor)].groupby(['author'],sort=True)['votes_minus'].count() 121 | dateFrame.plot(kind='bar',grid=True, rot=45) 122 | #Ответ @alizar 123 | 124 | #Сравните субботы и понедельники. Правда ли, что по субботам авторы пишут в основном днём, 125 | #а по понедельникам — в основном вечером? 126 | dateFrame=df.copy() 127 | dateFrame=dateFrame[(dateFrame.dayofweek.isin([1,6])) & (dateFrame.hour>=12)].groupby(['dayofweek','hour'],sort=True)['post_id'].count() 128 | dateFrame.plot(kind='bar',grid=True, rot=45) -------------------------------------------------------------------------------- /Анализ текстов.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Feb 28 15:08:44 2017 4 | 5 | @author: tehn-11 6 | """ 7 | 8 | #============================================================================== 9 | # Анализ текстов 10 | #============================================================================== 11 | from sklearn import datasets 12 | from sklearn.feature_extraction.text import TfidfVectorizer 13 | from sklearn.model_selection import GridSearchCV 14 | from sklearn.svm import SVC 15 | import numpy as np 16 | import pandas as pd 17 | from sklearn.model_selection import KFold 18 | 19 | #============================================================================== 20 | # Для начала вам потребуется загрузить данные. 21 | # В этом задании мы воспользуемся одним из датасетов, доступных в scikit-learn'е — 20 newsgroups. 22 | # Для этого нужно воспользоваться модулем datasets: 23 | #============================================================================== 24 | newsgroups = datasets.fetch_20newsgroups( 25 | subset='all', 26 | categories=['alt.atheism', 'sci.space'] 27 | ) 28 | 29 | #============================================================================== 30 | # Вычислите TF-IDF-признаки для всех текстов. 31 | # Обратите внимание, что в этом задании мы предлагаем вам вычислить TF-IDF по всем данным. 32 | # При таком подходе получается, что признаки на обучающем множестве используют информацию из тестовой выборки — но такая ситуация вполне законна, 33 | # поскольку мы не используем значения целевой переменной из теста. 34 | # На практике нередко встречаются ситуации, когда признаки объектов тестовой выборки известны на момент обучения, 35 | # и поэтому можно ими пользоваться при обучении алгоритма. 36 | #============================================================================== 37 | 38 | #В Scikit-Learn это реализовано в классе 39 | #sklearn.feature_extraction.text.TfidfVectorizer. 40 | #Преобразование обучающей выборки нужно делать с помощью функции fit_transform, тестовой — с помощью transform. 41 | y_train = newsgroups.target#Класс 42 | X_train = newsgroups.data#Характеристики 43 | 44 | vectorizer = TfidfVectorizer() 45 | dataMatrix=vectorizer.fit_transform(X_train).toarray()#матрица объектов по словам, в ячейках веса слов 46 | 47 | #idf = vectorizer.idf_ 48 | words=vectorizer.get_feature_names() 49 | #tf_idf=dict(zip(words, idf))#токены с весами 50 | 51 | 52 | #============================================================================== 53 | # Подберите минимальный лучший параметр C из множества [10^-5, 10^-4, ... 10^4, 10^5] для SVM с линейным ядром (kernel='linear') 54 | # при помощи кросс-валидации по 5 блокам. Укажите параметр random_state=241 и для SVM, и для KFold. 55 | # В качестве меры качества используйте долю верных ответов (accuracy). 56 | #============================================================================== 57 | 58 | grid = {'C': np.power(10.0, np.arange(-5, 6))} 59 | cv = KFold(n_splits=5, shuffle=True, random_state=241) 60 | clf = SVC(kernel='linear', random_state=241) 61 | gs = GridSearchCV(clf, grid, scoring='accuracy', cv=cv) 62 | gs.fit(dataMatrix, y_train)#внимание очень долго работает на тестовых данных 63 | 64 | #записываем параметры в массив 65 | #validationTest=dict(zip(gs.cv_results_['mean_test_score'], gs.cv_results_['params']))#получаем инфу по лучшему параметру в виде массива, который склеиваем с оценкой качества 66 | #validationTestData=pd.DataFrame(data=validationTest).transpose()#создаем датафрейм с транспонированием, покольку значения полявляются в колонках, а не строках 67 | #validationTestData.sort_index(ascending=[False],inplace=True) 68 | 69 | #У GridSearchCV есть поле best_estimator_, 70 | #которое можно использовать, чтобы не обучать заново классификатор с оптимальным параметром. 71 | bestC=gs.best_estimator_.C 72 | 73 | #устарело 74 | #for a in gs.grid_scores_: 75 | # validationTest[a.mean_validation_score]=a.parameters# — оценка качества по кросс-валидации и значения параметров 76 | 77 | #============================================================================== 78 | # Обучите SVM по всей выборке с оптимальным параметром C, найденным на предыдущем шаге. 79 | #============================================================================== 80 | clf = SVC(C=bestC,kernel='linear', random_state=241) 81 | result=clf.fit(dataMatrix, y_train) 82 | 83 | 84 | #============================================================================== 85 | # Найдите 10 слов с наибольшим абсолютным значением веса (веса хранятся в поле coef_ у svm.SVC). 86 | # Они являются ответом на это задание. Укажите эти слова через запятую или пробел, в нижнем регистре, 87 | #в лексикографическом порядке. 88 | #============================================================================== 89 | weights=[] 90 | for element in result.coef_.T:#с транспонированием, иначе все коэффициенты идут строкой 91 | weights.append(abs(element[0])) 92 | 93 | combine=dict(zip(words,weights)) 94 | bestWords=pd.DataFrame(data=combine,index=[0]).transpose()#с транспонированием, иначе все коэффициенты идут строкой 95 | bestWords.columns = ['weights']#переименуем колонки 96 | bestWords.sort_values(['weights'], ascending=[False],inplace=True) 97 | 98 | topTenWordsCollection=bestWords.head(10).index.values#берем значения 10 индексов (там слова) 99 | newWords=pd.DataFrame(data=topTenWordsCollection) 100 | newWords.columns = ['words']#переименуем колонки 101 | newWords.words.astype(str) 102 | newWords=newWords.apply(lambda x: x[0].lower(),axis =1)#приводим к нижнему регистру, имя колонки теряется 103 | newWords.sort_values(0, ascending=[True],inplace=True)#сортируем в лексикографическом порядке. 104 | 105 | collection=newWords.values#получаем значения массива 106 | print (' '.join(map(lambda x: x, collection)))#сливаем в строку каждый элемент 107 | 108 | -------------------------------------------------------------------------------- /Задание по программированию Выбор метрики Бостон.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sun Feb 26 12:11:38 2017 4 | 5 | @author: нзнегз 6 | """ 7 | import pandas 8 | import numpy 9 | from sklearn import datasets 10 | from sklearn.preprocessing import scale 11 | from sklearn.neighbors import KNeighborsRegressor 12 | from sklearn.model_selection import KFold 13 | from sklearn.model_selection import cross_val_score 14 | 15 | #Загрузите выборку Boston с помощью функции sklearn.datasets.load_boston(). 16 | #Результатом вызова данной функции является объект, у которого признаки 17 | #записаны в поле data, а целевой вектор — в поле target. 18 | boston=datasets.load_boston() 19 | 20 | # - CRIM per capita crime rate by town 21 | # - ZN proportion of residential land zoned for lots over 25,000 sq.ft. 22 | # - INDUS proportion of non-retail business acres per town 23 | # - CHAS Charles River dummy variable (= 1 if tract bounds river; 0 otherwise) 24 | # - NOX nitric oxides concentration (parts per 10 million) 25 | # - RM average number of rooms per dwelling 26 | # - AGE proportion of owner-occupied units built prior to 1940 27 | # - DIS weighted distances to five Boston employment centres 28 | # - RAD index of accessibility to radial highways 29 | # - TAX full-value property-tax rate per $10,000 30 | # - PTRATIO pupil-teacher ratio by town 31 | # - B 1000(Bk - 0.63)^2 where Bk is the proportion of blacks by town 32 | # - LSTAT % lower status of the population 33 | # - MEDV Median value of owner-occupied homes in $1000's 34 | data=pandas.DataFrame(data=boston.data,columns=boston.feature_names) 35 | target=pandas.DataFrame(data=boston.target) 36 | boston=0 37 | 38 | #Приведите признаки в выборке к одному масштабу при помощи функции sklearn.preprocessing.scale. 39 | dataScaled=scale(data)#масштабирование выполняется перед обучением 40 | data=0 41 | 42 | #Переберите разные варианты параметра метрики p по сетке от 1 до 10 с таким шагом, 43 | #чтобы всего было протестировано 200 вариантов (используйте функцию numpy.linspace). 44 | #Используйте KNeighborsRegressor с n_neighbors=5 и weights='distance' — данный параметр добавляет в алгоритм веса, 45 | #зависящие от расстояния до ближайших соседей. 46 | #В качестве метрики качества используйте среднеквадратичную ошибку (параметр scoring='mean_squared_error' у cross_val_score; 47 | #при использовании библиотеки scikit-learn версии 18.0.1 и выше необходимо указывать scoring='neg_mean_squared_error'). 48 | #Качество оценивайте, как и в предыдущем задании, с помощью кросс-валидации по 5 блокам с random_state = 42, 49 | #не забудьте включить перемешивание выборки (shuffle=True). 50 | kf = KFold(n_splits=5, shuffle=True, random_state=42)#кросс-валидация по 5 блокам с random_state = 42 с перемешиванием выборки 51 | 52 | #Полный формат вызова функции: numpy.linspace(start, stop, num = 50, endpoint = True, retstep = False), 53 | #где: 54 | #start - обязательный аргумент, первый член последовательности элементов массива; 55 | #stop - обязательный аргумент, последний член последовательности элементов массива; 56 | #num - опциональный аргумент, количество элементов массива, по умолчанию равен 50; 57 | #endpoint - опциональный аргумент, логическое значение, по умолчанию True. 58 | #Если передано True, stop, последний элемент массива. 59 | #Если установлено в False, последовательность элементов формируется от start до stop для num + 1 элементов, 60 | #при этом в возвращаемый массив последний элемент не входит; 61 | #retstep - опциональный аргумент, логическое значение, по умолчанию False. 62 | #Если передано True, функция возвращает кортеж из двух членов, 63 | #первый - массив, последовательность элементов, второй - число, приращение между элементами последовательности. 64 | p_parameter=numpy.linspace(1, 10, num = 200, endpoint = True, retstep = False) 65 | 66 | validationTest={} 67 | for parameter in p_parameter:#организуем цикл по p 68 | #Используйте KNeighborsRegressor с n_neighbors=5 и weights='distance' — данный параметр добавляет в алгоритм веса, 69 | #зависящие от расстояния до ближайших соседей. 70 | regression = KNeighborsRegressor(n_neighbors=5, weights='distance', p=parameter) 71 | regression.fit(dataScaled,target) 72 | scores=cross_val_score(regression, dataScaled, target, scoring='neg_mean_squared_error',cv=kf) 73 | validationTest[parameter] = round(scores.mean(),1) 74 | 75 | 76 | #формируем датасет для сортировки 77 | validationTestDataFrame=pandas.DataFrame.from_dict(validationTest, orient='index')#получаем из словаря датасет 78 | validationTestDataFrame.index.name = 'p' 79 | validationTestDataFrame.columns =['Scores'] 80 | validationTestDataFrame.sort_values(['Scores'], ascending=[False],inplace=True)#сортировка по убыванию значений 81 | print('Определите, при каком p качество на кросс-валидации оказалось оптимальным.'); 82 | print(validationTestDataFrame.head(1)) 83 | -------------------------------------------------------------------------------- /Неделя 3, Логистическая регрессия.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Mar 3 09:44:48 2017 4 | 5 | 6 | """ 7 | 8 | import pandas as pd 9 | from math import exp 10 | from scipy.spatial import distance 11 | from sklearn.metrics import roc_auc_score 12 | 13 | 14 | #============================================================================== 15 | # Загрузите данные из файла data-logistic.csv. Это двумерная выборка, целевая переменная на которой принимает значения -1 или 1. 16 | #============================================================================== 17 | 18 | data= pd.read_csv('data-logistic.csv',header=None) 19 | 20 | #============================================================================== 21 | # Реализуйте градиентный спуск (gradient descent) для обычной и 22 | # L2-регуляризованной (с коэффициентом регуляризации 10) логистической регрессии - это коэффициент C. 23 | # Используйте длину шага k=0.1. В качестве начального приближения используйте вектор (0, 0). 24 | #============================================================================== 25 | def GradientDescent(C,data): 26 | print('C=%d' %C) 27 | errorAccuracy=10**-5 28 | weights=[0.,0.] 29 | k=0.1#длина шага 30 | l=data[0].count()#количество элементов в выборке 31 | distance_euclidean=0 32 | 33 | weightsDelta=[0.,0.] 34 | for step in range(10000):#Рекомендуется ограничить сверху число итераций десятью тысячами. 35 | oldweightsDelta=weightsDelta 36 | weightsDelta=[0.,0.] 37 | 38 | for obj in data.values: 39 | y=obj[0] 40 | gradient=y*(1-1/(1+exp(-y*(weights[0]*obj[1]+weights[1]*obj[2])))) 41 | weightsDelta=list(map(lambda w,wd,x: wd+x*gradient-k*C*w,weights,weightsDelta,obj[1:])) 42 | 43 | #доведите до сходимости (евклидово расстояние между векторами весов на соседних итерациях должно быть не больше 1e-5) 44 | distance_euclidean=distance.euclidean(weightsDelta,oldweightsDelta) 45 | if distance_euclidean0.52:#проверка качества по целевому показателю 52 | validationTest[n_estimators]=val 53 | 54 | #============================================================================== 55 | # Определите, при каком минимальном количестве деревьев случайный лес показывает качество 56 | # на кросс-валидации выше 0.52. Это количество и будет ответом на задание. 57 | #============================================================================== 58 | #формируем датасет для сортировки 59 | validationTestDataFrame=pd.DataFrame.from_dict(validationTest, orient='index')#получаем из словаря датасет 60 | validationTestDataFrame.index.name = 'k' 61 | validationTestDataFrame.columns =['Scores'] 62 | validationTestDataFrame.sort_index(ascending=True,inplace=True) 63 | print('Определите, при каком минимальном количестве деревьев случайный лес показывает качество '); 64 | print(validationTestDataFrame.head(5)) 65 | 66 | 67 | -------------------------------------------------------------------------------- /Нормализация признаков Перцептрон.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mon Feb 27 21:44:28 2017 4 | 5 | @author: нзнегз 6 | """ 7 | import pandas 8 | from sklearn.preprocessing import StandardScaler 9 | from sklearn.linear_model import Perceptron 10 | from sklearn.metrics import accuracy_score 11 | 12 | 13 | #Загрузите обучающую и тестовую выборки из файлов perceptron-train.csv и perceptron-test.csv. 14 | #Целевая переменная записана в первом столбце, признаки — во втором и третьем. 15 | data= pandas.read_csv('perceptron-train.csv',header=None)#,names=['Class','Feature1','Feature2'] 16 | y_train = data[0]#Класс 17 | X_train = data.loc[:, 1:]#Характеристики 18 | 19 | #target_train = data.Class#вычленяем массив 20 | #model_train = data.drop(['Class'], axis=1)#Вычленяем модель из датасет 21 | 22 | data= pandas.read_csv('perceptron-test.csv',header=None)#,names=['Class','Feature1','Feature2'] 23 | y_test = data[0]#Класс 24 | X_test = data.loc[:, 1:]#Характеристики 25 | 26 | data=0 27 | 28 | #процедура обучения перцептрона 29 | def PerceptronTrain(typeStr,X_train, y_train,X_test,y_test): 30 | #Обучите персептрон со стандартными параметрами и random_state=241. 31 | clf = Perceptron(random_state=241) 32 | clf.fit(X_train, y_train) 33 | 34 | #В качестве метрики качества мы будем использовать долю верных ответов (accuracy). 35 | #Для ее подсчета можно воспользоваться функцией sklearn.metrics.accuracy_score, 36 | #первым аргументом которой является вектор правильных ответов, а вторым — вектор ответов алгоритма. 37 | #Подсчитайте качество (долю правильно классифицированных объектов, accuracy) полученного классификатора на тестовой выборке. 38 | predictions = clf.predict(X_test)#предсказание по тестовым данным 39 | accuracyScore=accuracy_score(y_test, predictions)#проверка точности по тестовым данным 40 | 41 | print('Подсчитайте качество '+typeStr) 42 | accuracyScoreRounded=round(accuracyScore,3) 43 | print(accuracyScoreRounded) 44 | return accuracyScoreRounded 45 | 46 | #обучаем перцептрон 47 | accuracyScoreGeneral=PerceptronTrain('без нормализации',X_train, y_train,X_test,y_test) 48 | 49 | #Нормализуйте обучающую и тестовую выборку с помощью класса StandardScaler 50 | scaler = StandardScaler() 51 | X_train_scaled = scaler.fit_transform(X_train) 52 | X_test_scaled = scaler.transform(X_test) 53 | 54 | #Обучите персептрон на новых выборках. Найдите долю правильных ответов на тестовой выборке. 55 | accuracyScoreScaled=PerceptronTrain('c нормализацией',X_train_scaled, y_train,X_test_scaled,y_test) 56 | 57 | #Найдите разность между качеством на тестовой выборке после нормализации и качеством до нее. Это число и будет ответом на задание. 58 | Comparation=accuracyScoreScaled-accuracyScoreGeneral 59 | print('Разница') 60 | print(Comparation) -------------------------------------------------------------------------------- /Опорные объекты.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Feb 28 11:08:35 2017 4 | 5 | @author: tehn-11 6 | """ 7 | #============================================================================== 8 | # Задание по программированию: Опорные объекты 9 | #============================================================================== 10 | import pandas 11 | from sklearn.svm import SVC 12 | 13 | #============================================================================== 14 | # Загрузите выборку из файла svm-data.csv. 15 | # В нем записана двумерная выборка (целевая переменная указана в первом столбце, признаки — во втором и третьем). 16 | #============================================================================== 17 | data = pandas.read_csv('svm-data.csv', header=None) 18 | y_train = data[0]#Класс 19 | X_train = data.loc[:, 1:]#Характеристики 20 | 21 | #============================================================================== 22 | # Обучите классификатор с линейным ядром, параметром C = 100000 и random_state=241. 23 | # Такое значение параметра нужно использовать, чтобы убедиться, 24 | # что SVM работает с выборкой как с линейно разделимой. 25 | # При более низких значениях параметра алгоритм будет настраиваться с учетом 26 | # слагаемого в функционале, штрафующего за маленькие отступы, 27 | # из-за чего результат может не совпасть с решением классической задачи SVM для линейно разделимой выборки. 28 | #============================================================================== 29 | clf = SVC(C = 100000,random_state=241,kernel='linear') 30 | clf.fit(X_train, y_train) 31 | 32 | #Индексы опорных объектов обученного классификатора хранятся в поле support_ 33 | print(clf.support_) -------------------------------------------------------------------------------- /Статистика по Титанику.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sat Feb 18 17:35:24 2017 4 | 5 | @author: нзнегз 6 | """ 7 | import pandas 8 | data = pandas.read_csv('titanic.csv', index_col='PassengerId') 9 | 10 | #Какое количество мужчин и женщин ехало на корабле? 11 | print('Какое количество мужчин и женщин ехало на корабле') 12 | print(data.Sex.value_counts()) 13 | 14 | 15 | #Какой части пассажиров удалось выжить? 16 | #Посчитайте долю выживших пассажиров. 17 | #Ответ приведите в процентах (число в интервале от 0 до 100, знак процента не нужен), округлив до двух знаков. 18 | print('Доля выживших пассажиров') 19 | #mask = data['Survived'] == 1 20 | #newdata=data[mask] 21 | #print(data.groupby('Survived').count()) 22 | 23 | onePercentTotal=data.Survived.count()/100 24 | survived=data.Survived.sum() 25 | print(round(survived/onePercentTotal,2)) 26 | 27 | #Какую долю пассажиры первого класса составляли среди всех пассажиров? 28 | #Ответ приведите в процентах (число в интервале от 0 до 100, знак процента не нужен), округлив до двух знаков. 29 | print('Доля пассажиров первого класса') 30 | data['FirstClassCounter']= 0#добавляем колонку со значением по умолчанию 31 | mask=data.Pclass == 1#маска выборки 32 | data.loc[mask,'FirstClassCounter']=1#выборка по колонке - будет счетчиком 33 | 34 | _firstClassCounter=data.FirstClassCounter.sum() 35 | print(round(_firstClassCounter/onePercentTotal,2)) 36 | 37 | 38 | #Какого возраста были пассажиры? 39 | #Посчитайте среднее и медиану возраста пассажиров. В качестве ответа приведите два числа через пробел. 40 | print('Посчитайте среднее и медиану возраста пассажиров') 41 | 42 | print(round(data.Age.mean(),2)) 43 | print(round(data.Age.median(),2)) 44 | 45 | #Диаграмма 46 | data['count']= 1 47 | data.pivot_table('Name', 'Pclass', 'Survived', 'count').plot(kind='bar', stacked=True) 48 | 49 | #Коррелируют ли число братьев/сестер/супругов с числом родителей/детей? 50 | #Посчитайте корреляцию Пирсона между признаками SibSp и Parch. 51 | print('Коррелируют ли число братьев/сестер/супругов с числом родителей/детей') 52 | df = pandas.DataFrame(data=data,columns=['SibSp', 'Parch']) 53 | print(round(df.corr().loc['SibSp','Parch'],2))#Пересечение двух областей 54 | 55 | #Какое самое популярное женское имя на корабле? Извлеките из полного имени пассажира (колонка Name) 56 | #его личное имя (First Name). Это задание — типичный пример того, с чем сталкивается специалист по анализу данных. 57 | #Данные очень разнородные и шумные, но из них требуется извлечь необходимую информацию. 58 | #Попробуйте вручную разобрать несколько значений столбца Name и выработать правило для извлечения имен, 59 | #а также разделения их на женские и мужские. 60 | print("Какое самое популярное женское имя на корабле") 61 | 62 | NameExtract=data.Name.str.extract('^.+?Mrs\..+?\((.+?)\)|^.+?Miss\.\s([\w\s]+)',expand=False)#первичное преобразование 63 | NameExtract.fillna('',inplace=True)#заменяем NULL на пустую строку 64 | NameExtract.columns = ['Mrs','Miss']#переименуем колонки 65 | NameExtract['CombinedName']=NameExtract.apply(lambda x:'%s%s' % (x['Mrs'],x['Miss']),axis=1)#соединяем в одну колонку 66 | NameExtract.drop(['Mrs','Miss'],axis=1,inplace=True)#удаляем ненужные колонки 67 | #print(NameExtract.CombinedName.str.split(' ')) 68 | 69 | femalenames=[] 70 | #обрабатываем список имен 71 | for i in range(NameExtract.CombinedName.count()): 72 | names=NameExtract.loc[i+1,'CombinedName'] 73 | words=names.split(' ') 74 | for word in words: 75 | if len(word)>2 and word.find('"'): 76 | femalenames.append(word) 77 | 78 | femalenamesDataFrame=pandas.DataFrame(data=femalenames,columns=['Names'])#получаем из листа датасет 79 | femalenamesDataFrame['count']= 1#колонка счетчик 80 | femalenamesDataFrameGroupBy=femalenamesDataFrame.groupby('Names').sum()#группируем по имени и суммируем счетчик 81 | femalenamesDataFrameSorted=femalenamesDataFrameGroupBy.sort_values(['count'], ascending=[False])#сортируем по счетчику в порядке убывания 82 | print(femalenamesDataFrameSorted.head(2))#показываем часто встечаемое имя 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /Финальное задание Игра Dota 2/Финальное задание final.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sat Apr 1 21:58:56 2017 4 | 5 | """ 6 | import pandas as pd 7 | from sklearn.ensemble import GradientBoostingClassifier 8 | from sklearn.model_selection import KFold 9 | from sklearn.model_selection import cross_val_score 10 | import datetime 11 | from sklearn.model_selection import GridSearchCV 12 | import numpy as np 13 | from sklearn.linear_model import LogisticRegression 14 | from sklearn.preprocessing import StandardScaler 15 | 16 | #============================================================================== 17 | # Считайте таблицу с признаками из файла features.csv с помощью кода, приведенного выше. 18 | # Удалите признаки, связанные с итогами матча (они помечены в описании данных как отсутствующие в тестовой выборке). 19 | #============================================================================== 20 | data_train = pd.read_csv('features.csv',index_col='match_id') 21 | data_test = pd.read_csv('features_test.csv',index_col='match_id') 22 | 23 | train_Y=data_train['radiant_win']#Целевая переменная 1, если победила команда Radiant, 0 — иначе 24 | columns_train_difference=data_train.columns.difference(data_test.columns.values.tolist()).tolist()#Удалите признаки, которых нет в тестовой выборке - получаем различие в колонках 25 | data_train.drop(columns_train_difference, axis=1, inplace=True)#удаляем внутри датасета 26 | 27 | #============================================================================== 28 | # Проверьте выборку на наличие пропусков с помощью функции count(), 29 | # которая для каждого столбца показывает число заполненных значений. 30 | # Много ли пропусков в данных? Запишите названия признаков, имеющих пропуски, и 31 | # попробуйте для любых двух из них дать обоснование, почему их значения могут быть пропущены. 32 | #============================================================================== 33 | train_size=data_train.shape[0] 34 | print("Select count=%s" % train_size) 35 | for col in data_train.columns.values.tolist(): 36 | count=data_train[col].count() 37 | if count!=train_size: 38 | print("Column %s, len=%s" % (col,count)) 39 | 40 | #============================================================================== 41 | # Замените пропуски на нули с помощью функции fillna(). На самом деле этот способ является предпочтительным для логистической регрессии, 42 | # поскольку он позволит пропущенному значению не вносить никакого вклада в предсказание. 43 | # Для деревьев часто лучшим вариантом оказывается замена пропуска на очень большое или очень маленькое значение — 44 | # в этом случае при построении разбиения вершины можно будет отправить объекты с пропусками в отдельную ветвь дерева. 45 | # Также есть и другие подходы — например, замена пропуска на среднее значение признака. Мы не требуем этого в задании, 46 | # но при желании попробуйте разные подходы к обработке пропусков и сравните их между собой. 47 | #============================================================================== 48 | # индекс, по которому будем отделять обучающую выборку от тестовой 49 | idx_split = train_size#индекс последнего элемента 50 | data_full = pd.concat([data_train, data_test])#формируем генеральную выборку из тренирующей и тестовой для одинаковой обработки 51 | del data_train,data_test 52 | 53 | #если заполнять большим значением, то качество модели улучшается на 0,5% 54 | #for col in data_full.columns.values.tolist(): 55 | #maxVal=data_full.loc[data_full[col].notnull(),col].max()**2 56 | #data_full.loc[data_full[col].isnull(),col]=maxVal#Заполняем все незаполненные значения данным результатом 57 | 58 | 59 | #Заполняем все незаполненные значения нулем 60 | data_full.fillna(0, method=None, axis=1, inplace=True)#зануляем пустые значения 61 | 62 | #============================================================================== 63 | # Какой столбец содержит целевую переменную? Запишите его название. 64 | #============================================================================== 65 | print('Целевая переменная=radiant_win') 66 | 67 | #============================================================================== 68 | # Забудем, что в выборке есть категориальные признаки, и попробуем обучить градиентный бустинг над деревьями на имеющейся матрице 69 | # "объекты-признаки". Зафиксируйте генератор разбиений для кросс-валидации по 5 блокам (KFold), 70 | # не забудьте перемешать при этом выборку (shuffle=True), поскольку данные в таблице отсортированы по времени, 71 | # и без перемешивания можно столкнуться с нежелательными эффектами при оценивании качества. 72 | # Оцените качество градиентного бустинга (GradientBoostingClassifier) с помощью данной кросс-валидации, 73 | # попробуйте при этом разное количество деревьев (как минимум протестируйте следующие значения для количества деревьев: 10, 20, 30). 74 | # Долго ли настраивались классификаторы? 75 | # Достигнут ли оптимум на испытанных значениях параметра n_estimators, или же качество, скорее всего, продолжит расти при дальнейшем его увеличении? 76 | #============================================================================== 77 | verbose=1 78 | 79 | kf = KFold(n_splits=5,shuffle=True)#Конструктор кросс-валидации 80 | 81 | #Проверяем гипотезу со стандартными настройками и заданным количеством деревьев 82 | print('Проверяем гипотезу со стандартными настройками и заданным количеством деревьев') 83 | for est in range(10,31,10): 84 | clf=GradientBoostingClassifier(n_estimators=est, random_state=241)#max_depth=3, n_estimators=70 Оценка качества=70.26 #**clf_grid.best_params_)#Передаем лучшие параметры в классификатор 85 | start_time = datetime.datetime.now() 86 | scores = cross_val_score(clf, data_full.iloc[:idx_split, :], train_Y, scoring='roc_auc', cv=kf)#Оценка алгоритма 87 | print('Time elapsed:', datetime.datetime.now() - start_time)#замеряем время 88 | val=round(scores.mean()*100,2)#берем среднее значение оценки 89 | print("n_estimators=%s, Оценка качества=%s" % (est,val)) 90 | 91 | 92 | #Проверяем гипотезу что увеличение количества деревьев улучшает качество с уменьшением глубины дерева и ускоряет процесс 93 | print('Проверяем гипотезу что увеличение количества деревьев улучшает качество с уменьшением глубины дерева и ускоряет процесс') 94 | param_grid = {'n_estimators':[60,70],'max_depth': range(3,5),'max_features': ["log2"]}#параметры сетки тестирования алгоритма 95 | clf_grid = GridSearchCV(GradientBoostingClassifier(random_state=241), param_grid,cv=kf, n_jobs=1,verbose=verbose,scoring='roc_auc') 96 | clf_grid.fit(data_full.iloc[:idx_split, :], train_Y) 97 | print("best_params") 98 | print(clf_grid.best_params_) 99 | 100 | clf=GradientBoostingClassifier(random_state=241,**clf_grid.best_params_) 101 | 102 | start_time = datetime.datetime.now() 103 | scores = cross_val_score(clf, data_full.iloc[:idx_split, :], train_Y, scoring='roc_auc', cv=kf)#Оценка алгоритма 104 | print('Time elapsed:', datetime.datetime.now() - start_time)#замеряем время 105 | val=round(scores.mean()*100,2)#берем среднее значение оценки 106 | print("Оценка качества=%s" % (val)) 107 | 108 | print('--------------------------') 109 | #============================================================================== 110 | # Оцените качество логистической регрессии (sklearn.linear_model.LogisticRegression с L2-регуляризацией) 111 | # с помощью кросс-валидации по той же схеме, которая использовалась для градиентного бустинга. 112 | # Подберите при этом лучший параметр регуляризации (C). Какое наилучшее качество у вас получилось? 113 | # Как оно соотносится с качеством градиентного бустинга? Чем вы можете объяснить эту разницу? 114 | # Быстрее ли работает логистическая регрессия по сравнению с градиентным бустингом? 115 | # Важно: не забывайте, что линейные алгоритмы чувствительны к масштабу признаков! 116 | # Может пригодиться sklearn.preprocessing.StandartScaler. 117 | #============================================================================== 118 | param_grid = {'C': np.logspace(-3, -1, 10)}#параметры сетки тестирования алгоритма - логарифмическая 119 | 120 | def getScoreLogisticRegression(text,data_train,saveToFile=False): 121 | clf_grid = GridSearchCV(LogisticRegression(random_state=241,n_jobs=-1), param_grid,cv=kf, n_jobs=1,verbose=verbose,scoring='roc_auc') 122 | clf_grid.fit(data_full.iloc[:idx_split, :], train_Y) 123 | 124 | lr=LogisticRegression(n_jobs=-1,random_state=241,**clf_grid.best_params_)#Создаем логистрическую регрессию с лучшими параметрами 125 | lr.fit(data_train.iloc[:idx_split, :], train_Y)#Обучаем 126 | start_time = datetime.datetime.now() 127 | scores = cross_val_score(lr, data_train.iloc[:idx_split, :], train_Y, scoring='roc_auc', cv=kf)#Оценка алгоритма 128 | print('Time elapsed:', datetime.datetime.now() - start_time)#замеряем время 129 | val=round(scores.mean()*100,2)#берем среднее значение оценки 130 | print("Оценка качества GridSearchCV (%s)=%s" % (text,val)) 131 | 132 | y_pred=pd.DataFrame(data=lr.predict_proba(data_train.iloc[idx_split:, :]))#прогнозируем 133 | y_pred.sort_values([1],inplace=True)#сортируем по значениям 134 | print(u'min=',y_pred.iloc[0,1],'; max=',y_pred.iloc[y_pred.shape[0]-1,1])#1 - класс означает, что Radiant победил 135 | 136 | if saveToFile: 137 | y_pred.sort_index(inplace=True) 138 | y_pred.to_csv('Radiant win predict',columns=[1],index_label=['match_id'],header=['prediction']) 139 | 140 | #обучаем без шкалирования 141 | getScoreLogisticRegression("without scaling",data_full) 142 | 143 | #попробуем шкалировать 144 | data_full_norm=pd.DataFrame(data=StandardScaler().fit_transform(data_full)) 145 | getScoreLogisticRegression("with scaling",data_full_norm) 146 | #============================================================================== 147 | # Среди признаков в выборке есть категориальные, которые мы использовали как числовые, 148 | # что вряд ли является хорошей идеей. Категориальных признаков в этой задаче одиннадцать: 149 | # lobby_type и r1_hero, r2_hero, ..., r5_hero, d1_hero, d2_hero, ..., d5_hero. 150 | # Уберите их из выборки, и проведите кросс-валидацию для логистической регрессии на новой выборке с подбором 151 | # лучшего параметра регуляризации. Изменилось ли качество? Чем вы можете это объяснить? 152 | #============================================================================== 153 | cols = ['r%s_hero' % i for i in range(1, 6)]+['d%s_hero' % i for i in range(1, 6)]#колонки героев 154 | cols.append('lobby_type') 155 | 156 | #удаляем категориальные данные, нормируем и повторно ищем лучший коэффициент 157 | data_full_norm=pd.DataFrame(data=StandardScaler().fit_transform(data_full.drop(cols, axis=1))) 158 | getScoreLogisticRegression("drop categories, with scaling",data_full_norm) 159 | print(u'кол-во колонок в матрице: ',len(data_full_norm.columns)) 160 | del data_full_norm 161 | 162 | #============================================================================== 163 | # #На предыдущем шаге мы исключили из выборки признаки rM_hero и dM_hero, которые показывают, 164 | # #какие именно герои играли за каждую команду. 165 | # #Это важные признаки — герои имеют разные характеристики, и некоторые из них выигрывают чаще, чем другие. 166 | # #Выясните из данных, сколько различных идентификаторов героев существует в данной игре 167 | # #(вам может пригодиться фукнция unique или value_counts). 168 | #============================================================================== 169 | cols.remove('lobby_type')#Убираем из списка колонок лишнюю, чтобы остались только герои 170 | iid=pd.Series(data_full[cols].values.flatten()).drop_duplicates() 171 | N=iid.shape[0] 172 | iid=pd.DataFrame(data=list(range(N)),index=iid.tolist())#переводим в обычный массив, чтобы индексация была чистая 173 | iid.sort_index(inplace=True)#хеш для героев 174 | print(u'сколько различных идентификаторов героев существует в данной игре: ',N) 175 | 176 | #============================================================================== 177 | # Воспользуемся подходом "мешок слов" для кодирования информации о героях. 178 | # Пусть всего в игре имеет N различных героев. 179 | # Сформируем N признаков, при этом i-й будет равен нулю, если i-й герой не участвовал в матче; единице, 180 | # если i-й герой играл за команду Radiant; минус единице, если i-й герой играл за команду Dire. 181 | # Ниже вы можете найти код, который выполняет данной преобразование. 182 | # Добавьте полученные признаки к числовым, которые вы использовали во втором пункте данного этапа. 183 | #============================================================================== 184 | # N — количество различных героев в выборке 185 | print('Старт dummy кодирования...') 186 | start_time = datetime.datetime.now() 187 | x_pick = pd.DataFrame(index=data_full.index,columns=range(0,N))#Датафрейм для dummy-переменных 188 | 189 | 190 | for match_id in data_full.index: 191 | row=data_full.ix[match_id,cols]#делаем слайс по строке и по нужным колонкам 192 | rowPick=x_pick.ix[match_id] 193 | for j, col in enumerate(row): 194 | rowPick[iid.ix[col,0]] = 1 if j<5 else -1#классификатор героя одной или другой команды 195 | 196 | x_pick.fillna(0, method=None, axis=1, inplace=True) 197 | print('Завершили. Time elapsed:', datetime.datetime.now() - start_time)#замеряем время 198 | 199 | totalFeatures=data_full.join(x_pick,rsuffix='_',how='outer')#pd.DataFrame(data=np.concatenate([x_pick,data_full_norm],axis=1)) 200 | del x_pick,iid 201 | 202 | cols.append('lobby_type') 203 | #Все нормируем и удаляем лишнее 204 | totalFeatures_norm=StandardScaler().fit_transform(totalFeatures.drop(cols, axis=1)) 205 | #============================================================================== 206 | # Проведите кросс-валидацию для логистической регрессии на новой выборке с подбором лучшего параметра регуляризации. 207 | # Какое получилось качество? Улучшилось ли оно? Чем вы можете это объяснить? 208 | # Постройте предсказания вероятностей победы команды Radiant для тестовой выборки с помощью лучшей из изученных 209 | # моделей (лучшей с точки зрения AUC-ROC на кросс-валидации). 210 | # Убедитесь, что предсказанные вероятности адекватные — находятся на отрезке [0, 1], 211 | # не совпадают между собой (т.е. что модель не получилась константной). 212 | #============================================================================== 213 | getScoreLogisticRegression("dummy coding",pd.DataFrame(data=totalFeatures_norm),True) 214 | -------------------------------------------------------------------------------- /Финальное задание Игра Dota 2/Финальное задание.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Mar 21 10:40:37 2017 4 | 5 | 6 | """ 7 | import pandas as pd 8 | from sklearn.ensemble import GradientBoostingClassifier 9 | from sklearn.model_selection import KFold 10 | from sklearn.model_selection import cross_val_score 11 | import datetime 12 | from sklearn.model_selection import GridSearchCV 13 | import numpy as np 14 | from sklearn.linear_model import LogisticRegression 15 | from sklearn.preprocessing import StandardScaler 16 | #from scipy.sparse import csr_matrix 17 | 18 | #============================================================================== 19 | # Считайте таблицу с признаками из файла features.csv с помощью кода, приведенного выше. 20 | # Удалите признаки, связанные с итогами матча (они помечены в описании данных как отсутствующие в тестовой выборке). 21 | #============================================================================== 22 | data_train = pd.read_csv('features.csv',index_col='match_id') 23 | data_test = pd.read_csv('features_test.csv',index_col='match_id') 24 | 25 | train_Y=data_train['radiant_win']#Целевая переменная 1, если победила команда Radiant, 0 — иначе 26 | columns_train_difference=data_train.columns.difference(data_test.columns.values.tolist()).tolist()#Удалите признаки, которых нет в тестовой выборке - получаем различие в колонках 27 | data_train.drop(columns_train_difference, axis=1, inplace=True)#удаляем внутри датасета 28 | 29 | 30 | #============================================================================== 31 | # Описание признаков в таблице 32 | # match_id: идентификатор матча в наборе данных 33 | # start_time: время начала матча (unixtime) 34 | # lobby_type: тип комнаты, в которой собираются игроки (расшифровка в dictionaries/lobbies.csv) 35 | # Наборы признаков для каждого игрока (игроки команды Radiant — префикс rN, Dire — dN): 36 | # r1_hero: герой игрока (расшифровка в dictionaries/heroes.csv) 37 | # r1_level: максимальный достигнутый уровень героя (за первые 5 игровых минут) 38 | # r1_xp: максимальный полученный опыт 39 | # r1_gold: достигнутая ценность героя 40 | # r1_lh: число убитых юнитов 41 | # r1_kills: число убитых игроков 42 | # r1_deaths: число смертей героя 43 | # r1_items: число купленных предметов 44 | # Признаки события "первая кровь" (first blood). Если событие "первая кровь" не успело произойти за первые 5 минут, то признаки принимают пропущенное значение 45 | # first_blood_time: игровое время первой крови 46 | # first_blood_team: команда, совершившая первую кровь (0 — Radiant, 1 — Dire) 47 | # first_blood_player1: игрок, причастный к событию 48 | # first_blood_player2: второй игрок, причастный к событию 49 | # Признаки для каждой команды (префиксы radiant_ и dire_) 50 | # radiant_bottle_time: время первого приобретения командой предмета "bottle" 51 | # radiant_courier_time: время приобретения предмета "courier" 52 | # radiant_flying_courier_time: время приобретения предмета "flying_courier" 53 | # radiant_tpscroll_count: число предметов "tpscroll" за первые 5 минут 54 | # radiant_boots_count: число предметов "boots" 55 | # radiant_ward_observer_count: число предметов "ward_observer" 56 | # radiant_ward_sentry_count: число предметов "ward_sentry" 57 | # radiant_first_ward_time: время установки командой первого "наблюдателя", т.е. предмета, который позволяет видеть часть игрового поля 58 | # Итог матча (данные поля отсутствуют в тестовой выборке, поскольку содержат информацию, выходящую за пределы первых 5 минут матча) 59 | # duration: длительность 60 | # radiant_win: 1, если победила команда Radiant, 0 — иначе 61 | # Состояние башен и барраков к концу матча (см. описание полей набора данных) 62 | # radiant_win 63 | # tower_status_dire 64 | # barracks_status_radiant 65 | # barracks_status_dire 66 | #============================================================================== 67 | 68 | #============================================================================== 69 | # Проверьте выборку на наличие пропусков с помощью функции count(), 70 | # которая для каждого столбца показывает число заполненных значений. 71 | # Много ли пропусков в данных? Запишите названия признаков, имеющих пропуски, и 72 | # попробуйте для любых двух из них дать обоснование, почему их значения могут быть пропущены. 73 | # 74 | #============================================================================== 75 | train_size=len(data_train) 76 | print("Select count=%s" % train_size) 77 | for col in data_train.columns.values.tolist(): 78 | count=data_train[col].count() 79 | if count!=train_size: 80 | print("Column %s, len=%s" % (col,count)) 81 | 82 | #============================================================================== 83 | # Select count=97230 84 | # Column first_blood_time, len=77677 - Если событие "первая кровь" не успело произойти за первые 5 минут, то признаки принимают пропущенное значение 85 | # Column first_blood_team, len=77677 - Если событие "первая кровь" не успело произойти за первые 5 минут, то признаки принимают пропущенное значение 86 | # Column first_blood_player1, len=77677 87 | # Column first_blood_player2, len=53243 88 | # Column radiant_bottle_time, len=81539 89 | # Column radiant_courier_time, len=96538 90 | # Column radiant_flying_courier_time, len=69751 91 | # Column radiant_first_ward_time, len=95394 92 | # Column dire_bottle_time, len=81087 93 | # Column dire_courier_time, len=96554 94 | # Column dire_flying_courier_time, len=71132 95 | # Column dire_first_ward_time, len=95404 96 | #============================================================================== 97 | verbose=1 98 | #============================================================================== 99 | # Замените пропуски на нули с помощью функции fillna(). На самом деле этот способ является предпочтительным для логистической регрессии, 100 | # поскольку он позволит пропущенному значению не вносить никакого вклада в предсказание. 101 | # Для деревьев часто лучшим вариантом оказывается замена пропуска на очень большое или очень маленькое значение — 102 | # в этом случае при построении разбиения вершины можно будет отправить объекты с пропусками в отдельную ветвь дерева. 103 | # Также есть и другие подходы — например, замена пропуска на среднее значение признака. Мы не требуем этого в задании, 104 | # но при желании попробуйте разные подходы к обработке пропусков и сравните их между собой. 105 | #============================================================================== 106 | 107 | # индекс, по которому будем отделять обучающую выборку от тестовой 108 | idx_split = data_train.shape[0]#индекс последнего элемента 109 | data_full = pd.concat([data_train, data_test])#формируем генеральную выборку из тренирующей и тестовой для одинаковой обработки 110 | #del data_train, data_test#удаляем дата сеты чтобы не мешались в памяти 111 | 112 | #Нужно найти все заполненные элементы 113 | #Вычислить максимум 114 | 115 | for col in data_full.columns.values.tolist(): 116 | maxVal=data_full.loc[data_full[col].notnull(),col].max()**2#max()**3#Считаем максимум по всем заполненным значением и берем квадрат 117 | data_full.loc[data_full[col].isnull(),col]=maxVal#Заполняем все незаполненные значения данным результатом 118 | 119 | 120 | #data_train.fillna(0, method=None, axis=1, inplace=True) 121 | 122 | 123 | #============================================================================== 124 | # Забудем, что в выборке есть категориальные признаки, и попробуем обучить градиентный бустинг над деревьями на имеющейся матрице 125 | # "объекты-признаки". Зафиксируйте генератор разбиений для кросс-валидации по 5 блокам (KFold), 126 | # не забудьте перемешать при этом выборку (shuffle=True), поскольку данные в таблице отсортированы по времени, 127 | # и без перемешивания можно столкнуться с нежелательными эффектами при оценивании качества. 128 | # Оцените качество градиентного бустинга (GradientBoostingClassifier) с помощью данной кросс-валидации, 129 | # попробуйте при этом разное количество деревьев (как минимум протестируйте следующие значения для количества деревьев: 10, 20, 30). 130 | # Долго ли настраивались классификаторы? 131 | # Достигнут ли оптимум на испытанных значениях параметра n_estimators, или же качество, скорее всего, продолжит расти при дальнейшем его увеличении? 132 | #============================================================================== 133 | 134 | kf = KFold(n_splits=5,shuffle=True)#Конструктор кросс-валидации 135 | 136 | 137 | #Проверяем гипотезу со стандартными настройками и заданным количеством деревьев 138 | print('Проверяем гипотезу со стандартными настройками и заданным количеством деревьев') 139 | for est in range(10,31,10): 140 | clf=GradientBoostingClassifier(n_estimators=est, random_state=241)#max_depth=3, n_estimators=70 Оценка качества=70.26 #**clf_grid.best_params_)#Передаем лучшие параметры в классификатор 141 | start_time = datetime.datetime.now() 142 | clf.fit(data_full.iloc[:idx_split, :], train_Y)#Обучаем 143 | print('Time elapsed:', datetime.datetime.now() - start_time)#замеряем время 144 | 145 | scores = cross_val_score(clf, data_full.iloc[:idx_split, :], train_Y, scoring='roc_auc', cv=kf)#Оценка алгоритма 146 | val=round(scores.mean()*100,2)#берем среднее значение оценки 147 | print("n_estimators=%s, Оценка качества=%s" % (est,val)) 148 | 149 | 150 | #Проверяем гипотезу что увеличение количества деревьев улучшает качество с уменьшением глубины дерева и ускоряет процесс 151 | print('Проверяем гипотезу что увеличение количества деревьев улучшает качество с уменьшением глубины дерева и ускоряет процесс') 152 | param_grid = {'n_estimators':[60,70],'max_depth': range(3,5),'max_features': ["log2"]}#параметры сетки тестирования алгоритма 153 | clf_grid = GridSearchCV(GradientBoostingClassifier(random_state=241), param_grid,cv=kf, n_jobs=1,verbose=verbose,scoring='roc_auc') 154 | clf_grid.fit(data_full.iloc[:idx_split, :], train_Y) 155 | print("best_params") 156 | print(clf_grid.best_params_) 157 | print("best_score") 158 | print(clf_grid.best_score_) 159 | 160 | 161 | #Пропущенное значение - очень большое число ^2 162 | #best_params {'max_depth': 4, 'max_features': 'log2', 'n_estimators': 70} 163 | #best_score 0.702832366129 164 | #Пропущенное значение - очень большое число ^3 165 | #best_params {'max_depth': 4, 'max_features': 'log2', 'n_estimators': 70} 166 | #best_score 0.7031630032570212.3566666666666666666660.2315.2333333333333333333333333333332 167 | #Пропущенное значение - медиана 168 | #best_params {'max_depth': 4, 'max_features': 'log2', 'n_estimators': 70} 169 | #best_score 0.702924164135 170 | #Оценка качества=70.29 171 | 172 | clf=GradientBoostingClassifier(**clf_grid.best_params_)#max_depth=3, n_estimators=70 Оценка качества=70.26 #**clf_grid.best_params_)#Передаем лучшие параметры в классификатор 173 | start_time = datetime.datetime.now() 174 | clf.fit(data_full.iloc[:idx_split, :], train_Y)#Обучаем 175 | print('Time elapsed:', datetime.datetime.now() - start_time)#замеряем время 176 | 177 | scores = cross_val_score(clf, data_full.iloc[:idx_split, :], train_Y, scoring='roc_auc', cv=kf)#Оценка алгоритма 178 | val=round(scores.mean()*100,2)#берем среднее значение оценки 179 | print("Оценка качества при увеличении числа деревьев=%s" % val) 180 | 181 | 182 | #получаем список показателей которые сильнее всего влияют на предсказания 183 | featureImportances=pd.DataFrame(data=clf.feature_importances_) 184 | featureImportances.sort_values([0],ascending=False,inplace=True) 185 | listCol=data_full.columns.values.tolist() 186 | 187 | 188 | #Оценка качества=70.25 189 | #1: d2_gold=8.43 190 | #2: r2_gold=8.3 191 | #3: d5_gold=8.01 192 | #4: d1_gold=7.87 193 | #5: r1_gold=7.81 194 | #6: d4_gold=7.77 195 | #7: r4_gold=7.61 196 | #8: r5_gold=7.47 197 | #9: r3_gold=7.28 198 | #10: d3_gold=7.07 199 | #11: first_blood_player1=2.37 200 | #12: radiant_boots_count=2.23 201 | 202 | #============================================================================== 203 | #Сводный график значений 204 | # import seaborn as sns 205 | # cols = ['d2_gold', 206 | # 'r2_gold', 207 | # 'd5_gold', 208 | # 'd1_gold', 209 | # 'r1_gold', 210 | # 'd4_gold', 211 | # 'r4_gold', 212 | # 'r5_gold', 213 | # 'r3_gold', 214 | # 'd3_gold'] 215 | # sns.pairplot(data_train[cols]) 216 | # 217 | #============================================================================== 218 | 219 | print('Характеристики которые вносят наибольший вклад в модель') 220 | count=1 221 | for i in featureImportances.index: 222 | if featureImportances.loc[i][0]<0.02: break 223 | print("%s: %s=%s" %(count,listCol[i],round(featureImportances.loc[i][0]*100,2))) 224 | count+=1 225 | 226 | 227 | 228 | #feature_importances_ : array, shape = [n_features] 229 | #The feature importances (the higher, the more important the feature). 230 | 231 | #start_time = datetime.datetime.now() 232 | 233 | #scores = cross_val_score(clf, data_train, train_Y, scoring='roc_auc', cv=kf)#Оценка алгоритма 234 | #print('Time elapsed:', datetime.datetime.now() - start_time)#замеряем время 235 | 236 | #val=round(scores.mean()*100,2)#берем среднее значение оценки 237 | #print("n_estimators=%s, val=%s\%" %(n_est,val)) 238 | 239 | 240 | #============================================================================== 241 | # Как долго проводилась кросс-валидация для градиентного бустинга с 30 деревьями? - около минуты 242 | # Какое качество при этом получилось? Напомним, что в данном задании мы используем метрику качества AUC-ROC. ~70% 243 | # Имеет ли смысл использовать больше 30 деревьев в градиентном бустинге? Думаю нет, время обучения увеличивается сильно, а качество повышается слабо 244 | # Что бы вы предложили делать, чтобы ускорить его обучение при увеличении количества деревьев? Уменьшить глубину деревьев и количество признаков, потеря точности небольшая (max_depth=4, max_features=sqrt, n_estimators=50, score=0.700039, total= 3.9s), а выигрыш во времени на порядок, использовать признаки имеющие максимальный вес при бустинге 245 | #============================================================================== 246 | 247 | print('--------------------------') 248 | #============================================================================== 249 | # Оцените качество логистической регрессии (sklearn.linear_model.LogisticRegression с L2-регуляризацией) 250 | # с помощью кросс-валидации по той же схеме, которая использовалась для градиентного бустинга. 251 | # Подберите при этом лучший параметр регуляризации (C). Какое наилучшее качество у вас получилось? 252 | # Как оно соотносится с качеством градиентного бустинга? Чем вы можете объяснить эту разницу? 253 | # Быстрее ли работает логистическая регрессия по сравнению с градиентным бустингом? 254 | # Важно: не забывайте, что линейные алгоритмы чувствительны к масштабу признаков! 255 | # Может пригодиться sklearn.preprocessing.StandartScaler. 256 | #============================================================================== 257 | data_full = pd.concat([data_train, data_test])#формируем генеральную выборку из тренирующей и тестовой для одинаковой обработки 258 | data_full.index=range(0,len(data_full))#реиндексируем, иначе поиск по индексу работает некорректно 259 | del data_train, data_test#удаляем дата сеты чтобы не мешались в памяти 260 | data_full.fillna(0, method=None, axis=1, inplace=True)#для логистической регрессии зануляем пустые значения 261 | 262 | 263 | param_grid = {'C': np.logspace(-3, -1, 10)}#параметры сетки тестирования алгоритма - логарифмическая 264 | #param_grid = {'C': np.linspace(0.003, 0.008, 20)}#параметры сетки тестирования алгоритма - линейная 265 | 266 | #Поиск лучшего коэффициента обучения 267 | #print('Поиск лучшего коэффициента обучения') 268 | 269 | def getScoreLogisticRegression(text,data_train,saveToFile=False): 270 | clf_grid = GridSearchCV(LogisticRegression(random_state=241,n_jobs=-1), param_grid,cv=kf, n_jobs=1,verbose=verbose,scoring='roc_auc') 271 | clf_grid.fit(data_full.iloc[:idx_split, :], train_Y) 272 | #print(u"best_params") 273 | #print(clf_grid.best_params_) 274 | #print(u"best_score") 275 | #print(clf_grid.best_score_) 276 | 277 | 278 | lr=LogisticRegression(n_jobs=-1,random_state=241,**clf_grid.best_params_)#Создаем логистрическую регрессию с лучшими параметрами 279 | lr.fit(data_train.iloc[:idx_split, :], train_Y)#Обучаем 280 | scores = cross_val_score(lr, data_train.iloc[:idx_split, :], train_Y, scoring='roc_auc', cv=kf)#Оценка алгоритма 281 | val=round(scores.mean()*100,2)#берем среднее значение оценки 282 | print("Оценка качества GridSearchCV (%s)=%s" % (text,val)) 283 | 284 | y_pred=pd.DataFrame(data=lr.predict_proba(data_train.iloc[idx_split:, :]))#прогнозируем 285 | y_pred.sort_values([0],inplace=True)#сортируем 286 | print(u'min=',y_pred.iloc[0,1],'; max=',y_pred.iloc[y_pred.shape[0]-1,1])#1 - класс означает, что Radiant победил 287 | 288 | if saveToFile: 289 | y_pred.sort_index(inplace=True) 290 | y_pred.to_csv('Radiant win predict',columns=[1],index_label=['match_id'],header=['prediction']) 291 | 292 | 293 | 294 | getScoreLogisticRegression("without scaling",data_full) 295 | 296 | #best_params whithot scaling 297 | #{'C': 1.0000000000000001e-05} 298 | #best_score whithot scaling 299 | #0.557243278127 300 | 301 | #попробуем шкалировать 302 | data_full_norm=pd.DataFrame(data=StandardScaler().fit_transform(data_full)) 303 | getScoreLogisticRegression("with scaling",data_full_norm) 304 | 305 | del data_full_norm 306 | #best_params with scaling 307 | #{'C': 0.0037275937203149379} 308 | #best_score with scaling 309 | #0.71587143058 310 | 311 | #best_params with scaling 312 | #{'C': 0.0071968567300115215} 313 | #best_score with scaling 314 | #0.716081358437 315 | 316 | #best_params with scaling 317 | #{'C': 0.0047142857142857143} 318 | #best_score with scaling 319 | #0.715872172211 320 | 321 | #Какое качество получилось у логистической регрессии над всеми исходными признаками? - Без нормализации дает значительно худший результат (0.557243278127), после нормализации чуть лучший чем градиентный бустинг (0.71587143058) 322 | #Как оно соотносится с качеством градиентного бустинга? 323 | #Чем вы можете объяснить эту разницу? - Влияют сами данные, их нормализация и присутствие категориальных признаков 324 | #Быстрее ли работает логистическая регрессия по сравнению с градиентным бустингом? - Работает быстрее 325 | 326 | #============================================================================== 327 | # Среди признаков в выборке есть категориальные, которые мы использовали как числовые, 328 | # что вряд ли является хорошей идеей. Категориальных признаков в этой задаче одиннадцать: 329 | # lobby_type и r1_hero, r2_hero, ..., r5_hero, d1_hero, d2_hero, ..., d5_hero. 330 | # Уберите их из выборки, и проведите кросс-валидацию для логистической регрессии на новой выборке с подбором 331 | # лучшего параметра регуляризации. Изменилось ли качество? Чем вы можете это объяснить? 332 | #============================================================================== 333 | cols = ['r%s_hero' % i for i in range(1, 6)]+['d%s_hero' % i for i in range(1, 6)]#колонки героев 334 | cols.append('lobby_type') 335 | 336 | #удаляем категориальные данные, нормируем и повторно ищем лучший коэффициент 337 | data_full_norm=pd.DataFrame(data=StandardScaler().fit_transform(data_full.drop(cols, axis=1))) 338 | getScoreLogisticRegression("drop categories, with scaling",data_full_norm) 339 | 340 | #best_params drop categories, with scaling 341 | #{'C': 0.0037275937203149379} 342 | #best_score drop categories, with scaling 343 | #0.715900195147 344 | 345 | #best_params drop categories, with scaling 346 | #{'C': 0.0055263157894736847} 347 | #best_score drop categories, with scaling 348 | #0.715911754352 349 | 350 | #best_params drop categories, with scaling 351 | #{'C': 0.0042813323987193957} 352 | #best_score drop categories, with scaling 353 | #0.715990354582 354 | 355 | #best_params drop categories, with scaling 356 | #{'C': 0.0051794746792312128} 357 | #best_score drop categories, with scaling 358 | #0.716022599382 359 | 360 | #============================================================================== 361 | # Как влияет на качество логистической регрессии удаление категориальных признаков (укажите новое значение метрики качества)? - Обучается чуть лучше, едва заметно 362 | # Чем вы можете объяснить это изменение? - уменьшение размерности модели, как минимум не ухудшает прогнозируемость, линейные модели не очень хорошо работают с категориальными объектами в отличии от деревьев 363 | #============================================================================== 364 | 365 | #На предыдущем шаге мы исключили из выборки признаки rM_hero и dM_hero, которые показывают, 366 | #какие именно герои играли за каждую команду. 367 | #Это важные признаки — герои имеют разные характеристики, и некоторые из них выигрывают чаще, чем другие. 368 | #Выясните из данных, сколько различных идентификаторов героев существует в данной игре 369 | #(вам может пригодиться фукнция unique или value_counts). 370 | cols.remove('lobby_type')#elfkztv из списка колонок лишнюю, чтобы остались только герои 371 | iid=pd.Series(data_full[cols].values.flatten()).drop_duplicates() 372 | N=iid.shape[0] 373 | iid=pd.DataFrame(data=list(range(N)),index=iid.tolist())#переводим в обычный массив, чтобы индексация была чистая 374 | iid.sort_index(inplace=True) 375 | print(u'сколько различных идентификаторов героев существует в данной игре: ',N) 376 | 377 | #сколько различных идентификаторов героев существует в данной игре: 108 378 | 379 | #============================================================================== 380 | # Воспользуемся подходом "мешок слов" для кодирования информации о героях. 381 | # Пусть всего в игре имеет N различных героев. 382 | # Сформируем N признаков, при этом i-й будет равен нулю, если i-й герой не участвовал в матче; единице, 383 | # если i-й герой играл за команду Radiant; минус единице, если i-й герой играл за команду Dire. 384 | # Ниже вы можете найти код, который выполняет данной преобразование. 385 | # Добавьте полученные признаки к числовым, которые вы использовали во втором пункте данного этапа. 386 | #============================================================================== 387 | # N — количество различных героев в выборке 388 | print('Старт dummy кодирования...') 389 | start_time = datetime.datetime.now() 390 | #x_pick = pd.DataFrame(index=data_full_norm.index,columns=range(0,N))#Датафрейм для dummy-переменных 391 | 392 | 393 | #for match_id in data_full.index: 394 | # row=data_full.ix[match_id,cols]#делаем слайс по строке и по нужным колонкам 395 | # rowPick=x_pick.ix[match_id] 396 | # for j, col in enumerate(row): 397 | # rowPick[iid.ix[col,0]] = 1 if j<5 else -1#классификатор героя одной или другой команды 398 | # 399 | #x_pick.fillna(0, method=None, axis=1, inplace=True) 400 | 401 | x_pick_d = pd.get_dummies(data_full[cols[5:]].astype('str')) 402 | x_pick_r = pd.get_dummies(data_full[cols[:5]].astype('str')) 403 | x_pick_r *= -1 404 | x_pick_d.columns=[col[1:] for col in list(x_pick_d.columns)]#убираем в колонках принадлежность к классам 405 | x_pick_r.columns=[col[1:] for col in list(x_pick_r.columns)]#убираем в колонках принадлежность к классам 406 | 407 | x_pick=x_pick_d+x_pick_r 408 | del x_pick_d,x_pick_r 409 | 410 | 411 | print('Завершили. Time elapsed:', datetime.datetime.now() - start_time)#замеряем время 412 | 413 | total=data_full_norm.join(x_pick,rsuffix='_',how='inner')#pd.DataFrame(data=np.concatenate([x_pick,data_full_norm],axis=1)) 414 | del x_pick,data_full_norm 415 | getScoreLogisticRegression("dummy coding",total,True) 416 | 417 | 418 | #getScoreLogisticRegression("sparse matrix",data_full_norm_norm_sparse) 419 | #del data_full_norm_norm_sparse 420 | 421 | #best_params sparse matrix 422 | #{'C': 0.071968567300115208} 423 | #best_score sparse matrix 424 | #0.751559380639 425 | 426 | #best_params sparse matrix 427 | #{'C': 0.037275937203149381} 428 | #best_score sparse matrix 429 | #0.751590669294 430 | 431 | #best_params sparse matrix 432 | #{'C': 0.061054022965853265} 433 | #best_score sparse matrix 434 | #0.751886025993 435 | 436 | #============================================================================== 437 | # Какое получилось качество при добавлении "мешка слов" по героям? - 0.751559380639 438 | # Улучшилось ли оно по сравнению с предыдущим вариантом? - да, улучшилось 439 | # Чем вы можете это объяснить? Переход из категориального кодирования на dummy кодирование - улучшает прогнозирование по модели на линейных методах 440 | #============================================================================== 441 | 442 | #============================================================================== 443 | # Какое минимальное и максимальное значение прогноза на тестовой выборке получилось у лучшего из алгоритмов? 444 | #============================================================================== 445 | 446 | #============================================================================== 447 | # Select count=97230 448 | # Column first_blood_time, len=77677 449 | # Column first_blood_team, len=77677 450 | # Column first_blood_player1, len=77677 451 | # Column first_blood_player2, len=53243 452 | # Column radiant_bottle_time, len=81539 453 | # Column radiant_courier_time, len=96538 454 | # Column radiant_flying_courier_time, len=69751 455 | # Column radiant_first_ward_time, len=95394 456 | # Column dire_bottle_time, len=81087 457 | # Column dire_courier_time, len=96554 458 | # Column dire_flying_courier_time, len=71132 459 | # Column dire_first_ward_time, len=95404 460 | # Проверяем гипотезу со стандартными настройками и заданным количеством деревьев 461 | # Time elapsed: 0:00:04.749582 462 | # n_estimators=10, Оценка качества=66.74 463 | # Time elapsed: 0:00:08.723383 464 | # n_estimators=20, Оценка качества=68.36 465 | # Time elapsed: 0:00:13.144788 466 | # n_estimators=30, Оценка качества=69.05 467 | # Проверяем гипотезу что увеличение количества деревьев улучшает качество с уменьшением глубины дерева и ускоряет процесс 468 | # Fitting 10 folds for each of 4 candidates, totalling 40 fits 469 | # [Parallel(n_jobs=1)]: Done 40 out of 40 | elapsed: 2.5min finished 470 | # best_params 471 | # {'max_depth': 4, 'max_features': 'log2', 'n_estimators': 70} 472 | # best_score 473 | # 0.703331166405 474 | # Time elapsed: 0:00:04.665730 475 | # Оценка качества при увеличении числа деревьев=70.34 476 | # Характеристики которые вносят наибольший вклад в модель 477 | # 1: d2_gold=5.47 478 | # 2: d1_gold=5.1 479 | # 3: r2_gold=5.05 480 | # 4: r1_gold=4.8 481 | # 5: d3_gold=4.54 482 | # 6: r4_gold=4.33 483 | # 7: d4_gold=4.32 484 | # 8: r5_gold=3.87 485 | # 9: d5_gold=3.86 486 | # 10: r3_gold=2.72 487 | # 11: d5_lh=2.65 488 | # 12: r3_lh=2.35 489 | # 13: r4_lh=2.34 490 | # 14: d1_lh=2.12 491 | # 15: radiant_boots_count=2.09 492 | # -------------------------- 493 | # Fitting 10 folds for each of 10 candidates, totalling 100 fits 494 | # [Parallel(n_jobs=1)]: Done 100 out of 100 | elapsed: 52.9s finished 495 | # Оценка качества GridSearchCV (without scaling)=51.35 496 | # min= 0.481385096984 ; max= 0.48164115994 497 | # Fitting 10 folds for each of 10 candidates, totalling 100 fits 498 | # [Parallel(n_jobs=1)]: Done 100 out of 100 | elapsed: 49.8s finished 499 | # Оценка качества GridSearchCV (with scaling)=71.63 500 | # min= 0.0168678616386 ; max= 0.989858087529 501 | # Fitting 10 folds for each of 10 candidates, totalling 100 fits 502 | # [Parallel(n_jobs=1)]: Done 100 out of 100 | elapsed: 49.2s finished 503 | # Оценка качества GridSearchCV (drop categories, with scaling)=71.64 504 | # min= 0.0172399825669 ; max= 0.989852747144 505 | # сколько различных идентификаторов героев существует в данной игре: 108 506 | # Старт dummy кодирования... 507 | # Завершили. Time elapsed: 0:03:41.448749 508 | # Fitting 10 folds for each of 10 candidates, totalling 100 fits 509 | # [Parallel(n_jobs=1)]: Done 100 out of 100 | elapsed: 49.6s finished 510 | # Оценка качества GridSearchCV (dummy coding)=74.68 511 | # min= 0.00775904001868 ; max= 0.990233686565 512 | #============================================================================== 513 | -------------------------------------------------------------------------------- /Характеристики вин.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sat Feb 25 13:27:46 2017 4 | 5 | @author: нзнегз 6 | """ 7 | 8 | #Характеристики вин 9 | import pandas 10 | from sklearn.model_selection import KFold 11 | from sklearn.model_selection import cross_val_score 12 | from sklearn.preprocessing import scale 13 | from sklearn.neighbors import KNeighborsClassifier 14 | 15 | #Загрузите выборку Wine по адресу 16 | #https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data (файл также приложен к этому заданию) 17 | data = pandas.read_csv('wine.data') 18 | 19 | #Извлеките из данных признаки и классы. Класс записан в первом столбце 20 | #(три варианта), признаки — в столбцах со второго по последний. 21 | #Более подробно о сути признаков можно прочитать по адресу 22 | #https://archive.ics.uci.edu/ml/datasets/Wine (см. также файл wine.names, приложенный к заданию) 23 | data.columns = ['Class','Alcohol','MalicAcid','Ash','AlcalinityOfAsh','Magnesium','TotalPhenols','Flavanoids','NonflavanoidPhenols','Proanthocyanins','ColorIntensity','Hue','OD280_OD315OfDilutedWines','Proline'] 24 | target = data.Class#вычленяем массив 25 | model = data.drop(['Class'], axis=1)#Вычленяем модель из датасет 26 | 27 | 28 | #Оценку качества необходимо провести методом кросс-валидации по 5 блокам (5-fold). 29 | #Создайте генератор разбиений, который перемешивает выборку перед формированием блоков (shuffle=True). 30 | #Для воспроизводимости результата, создавайте генератор KFold с фиксированным параметром random_state=42. 31 | #В качестве меры качества используйте долю верных ответов (accuracy). 32 | kf = KFold(n_splits=5, shuffle=True, random_state=42) 33 | 34 | #Вычислить качество на всех разбиениях можно при помощи функции sklearn.model_selection.cross_val_score. 35 | #В качестве параметра estimator передается классификатор, 36 | #в качестве параметра cv — генератор разбиений с предыдущего шага. 37 | #С помощью параметра scoring можно задавать меру качества, 38 | #по умолчанию в задачах классификации используется доля верных ответов (accuracy). 39 | #Результатом является массив, значения которого нужно усреднить. 40 | 41 | #Найдите точность классификации на кросс-валидации для метода k ближайших соседей 42 | #(sklearn.neighbors.KNeighborsClassifier), при k от 1 до 50. 43 | #При каком k получилось оптимальное качество? Чему оно равно (число в интервале от 0 до 1)? 44 | #Данные результаты и будут ответами на вопросы 1 и 2. 45 | 46 | 47 | def CalculateScores(model,count): 48 | validationTest={} 49 | for k in range(50):#счетчик идет от нуля 50 | model_knc = KNeighborsClassifier(n_neighbors = (k+1)) #в параметре передаем кол-во соседей 51 | scores = cross_val_score(model_knc, model, target, scoring='accuracy',cv=kf) 52 | validationTest[k+1]=scores.mean()#берем среднее значение оценки 53 | 54 | #формируем датасет для сортировки 55 | validationTestDataFrame=pandas.DataFrame.from_dict(validationTest, orient='index')#получаем из словаря датасет 56 | validationTestDataFrame.index.name = 'k' 57 | validationTestDataFrame.columns =['Scores'] 58 | validationTestDataFrame.sort_values(['Scores'], ascending=[False],inplace=True) 59 | print('При каком k получилось оптимальное качество? Чему оно равно (число в интервале от 0 до 1)? Данные результаты и будут ответами на вопросы 1 и 2.'); 60 | print(validationTestDataFrame.head(count)) 61 | 62 | CalculateScores(model,1) 63 | #Произведите масштабирование признаков с помощью функции sklearn.preprocessing.scale. 64 | model2=scale(model)#масштабирование выполняется перед обучением 65 | CalculateScores(model2,11)#Снова найдите оптимальное k на кросс-валидации. 66 | 67 | #Какое значение k получилось оптимальным после приведения признаков к одному масштабу? 68 | #Приведите ответы на вопросы 3 и 4. Помогло ли масштабирование признаков? 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /бустинг имитации отжига 4.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Aug 23 12:19:37 2019 4 | 5 | @author: Belov 6 | """ 7 | #LICENSE ON christofides_tsp 8 | #======= 9 | #Copyright (c) 2016 D. S. Rahul 10 | #Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | #The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 12 | #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 13 | 14 | #Имитация отжига (С) 2019,2016 Белов С.В.,D. S. Rahul 15 | #mail@belovsergey.ru 16 | 17 | import pandas as pd 18 | import os 19 | import numpy as np 20 | from itertools import cycle, dropwhile, islice 21 | import random 22 | from multiprocessing import Process, Queue 23 | import tqdm 24 | import sys 25 | import re 26 | #import io 27 | #import json 28 | from pytsp.christofides_tsp import christofides_tsp 29 | import time 30 | #---------------------------------------------- 31 | 32 | import time 33 | start_time = time.time() 34 | from math import sin, cos, sqrt, atan2, radians 35 | from scipy.spatial.distance import pdist, squareform 36 | 37 | class ReadData(): 38 | def __init__(self, filename): 39 | 40 | self.name = filename[:-4] 41 | self.size = self.getSize() 42 | self.EdgeWeightType = self.getEdgeWeightType() 43 | self.format_ = self.getFormat() # for EXPLICIT data only 44 | self.time_to_read = 0 45 | 46 | def getFormat(self): 47 | format_ = "None" 48 | try: 49 | with open(f'{self.name}.tsp') as data:#TSP_Data/ 50 | datalist = data.read().split() 51 | for ind, elem in enumerate(datalist): 52 | if elem == "EDGE_WEIGHT_FORMAT:": 53 | format_ = datalist[ind + 1] 54 | break 55 | elif elem == "EDGE_WEIGHT_FORMAT": 56 | format_ = datalist[ind + 2] 57 | break 58 | return format_ 59 | 60 | except IOError: 61 | print("Input file "+self.name+" not found") 62 | sys.exit(1) 63 | 64 | def getEdgeWeightType(self): 65 | EdgeType = "None" 66 | try: 67 | with open(f'{self.name}.tsp') as data:#TSP_Data/ 68 | datalist = data.read().split() 69 | for ind, elem in enumerate(datalist): 70 | if elem == "EDGE_WEIGHT_TYPE:": 71 | EdgeType = datalist[ind + 1] 72 | #print(EdgeType) 73 | break 74 | elif elem == "EDGE_WEIGHT_TYPE": 75 | EdgeType = datalist[ind + 2] 76 | #print(EdgeType) 77 | break 78 | return EdgeType 79 | 80 | except IOError: 81 | print("Input file "+self.name+" not found") 82 | sys.exit(1) 83 | 84 | def getSize(self): 85 | """ 86 | Return size of instances (i.e. Number of 87 | cities) 88 | 89 | """ 90 | size = 0 91 | try: 92 | with open(f'{self.name}.tsp') as data:#TSP_Data/ 93 | datalist = data.read().split() 94 | for ind, elem in enumerate(datalist): 95 | if elem == "DIMENSION:": 96 | size = datalist[ind + 1] 97 | #print(size) 98 | break 99 | elif elem == "DIMENSION": 100 | size = datalist[ind + 2] 101 | #print(size) 102 | break 103 | return int(size) 104 | except IOError: 105 | print("Input file "+self.name+" not found") 106 | sys.exit(1) 107 | 108 | def read_Data(self): 109 | with open(f'{self.name}.tsp') as data:#TSP_Data/ 110 | cities = [] 111 | Isdata = True 112 | while (Isdata): 113 | line = data.readline().split() 114 | if len(line) <= 0: 115 | break 116 | tempcity = [] 117 | for i, elem in enumerate(line): 118 | try: 119 | temp = float(elem) 120 | tempcity.append(temp) 121 | except ValueError: 122 | break 123 | if len(tempcity) > 0: 124 | cities.append(np.array(tempcity)) 125 | return np.array(cities) 126 | 127 | def GetDistanceMat(self): 128 | if self.EdgeWeightType == "EXPLICIT": 129 | DistanceMat = self.getMat() 130 | self.time_to_read = time.time() - start_time 131 | return DistanceMat 132 | elif self.EdgeWeightType == "EUC_2D" or "CEIL_2D": 133 | DistanceMat = self.EuclidDist() 134 | self.time_to_read = time.time() - start_time 135 | return DistanceMat 136 | elif self.EdgeWeightType == "GEO": 137 | DistanceMat = self.GeographicDist() 138 | self.time_to_read = time.time() - start_time 139 | return DistanceMat 140 | else: 141 | return None 142 | 143 | def EuclidDist(self): 144 | cities = self.read_Data() 145 | #DistanceDict = {} 146 | A = cities[:, 1:3] 147 | DistanceMat = np.round(squareform(pdist(A))) 148 | return DistanceMat 149 | 150 | def GeographicDist(self): 151 | a = time.time() 152 | R = 6373.0 153 | cities = self.read_Data() 154 | DistanceMat = np.zeros((self.size, self.size)) 155 | for i in range(self.size): 156 | for j in range(0, i + 1): 157 | node1 = cities[i] 158 | node2 = cities[j] 159 | lat1 = radians(node1[1]) 160 | lat1 = radians(node1[1]) 161 | lon1 = radians(node1[2]) 162 | lat2 = radians(node2[1]) 163 | lon2 = radians(node2[2]) 164 | dlon = lon2 - lon1 165 | dlat = lat2 - lat1 166 | a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2 167 | c = 2 * atan2(sqrt(a), sqrt(1 - a)) 168 | distance = R * c 169 | DistanceMat[i, j] = distance 170 | DistanceMat[j, i] = distance 171 | 172 | return DistanceMat 173 | 174 | def getMat(self): 175 | DataFormat = self.getFormat() 176 | if DataFormat == "FULL_MATRIX": 177 | cities = self.read_Data() 178 | DistanceMat = cities[:self.size] 179 | return DistanceMat 180 | 181 | elif DataFormat == "LOWER_DIAG_ROW": 182 | with open(f'{self.name}.tsp') as file:#TSP_Data/ 183 | indicator = False 184 | data = file.read().split() 185 | templist = [] 186 | cities = [] 187 | for elem in data: 188 | if elem == "EDGE_WEIGHT_SECTION": 189 | indicator = True 190 | continue 191 | if indicator: 192 | try: 193 | it = float(elem) 194 | templist.append(it) 195 | except: 196 | break 197 | if it == 0: 198 | cities.append(templist) 199 | templist = [] 200 | DistanceMat = np.zeros((self.size, self.size)) 201 | for i in range(self.size): 202 | temp = [] 203 | l = len(cities[i]) 204 | for j in range(self.size): 205 | if j <= (l - 1): 206 | temp.append(cities[i][j]) 207 | else: 208 | temp.append(cities[j][i]) 209 | DistanceMat[i] = temp 210 | return DistanceMat 211 | elif DataFormat == "UPPER_DIAG_ROW": 212 | with open(f'{self.name}.tsp') as file:#TSP_Data/ 213 | indicator = False 214 | data = file.read().split() 215 | templist = [] 216 | cities = [] 217 | for elem in data: 218 | if elem == "EDGE_WEIGHT_SECTION": 219 | indicator = True 220 | continue 221 | if indicator: 222 | try: 223 | it = float(elem) 224 | templist.append(it) 225 | except ValueError: 226 | break 227 | if it == 0: 228 | cities.append(templist) 229 | templist = [] 230 | print("Need to complete it") 231 | else: 232 | sys.exit("No Format Match for EXPLICIT data") 233 | 234 | 235 | 236 | 237 | 238 | def read_file(file): 239 | file_data=pd.read_csv(file , sep=';', header=0,encoding='utf-8')#читаем файл 240 | 241 | #Трансформируем в матрицу 242 | #Сначала получаем список уникальных ячеек 243 | cols=np.concatenate((file_data['Ячейка1'].unique(),file_data['Ячейка2'].unique()), axis=0) 244 | cols=np.unique(cols, axis=0) 245 | 246 | #теперь формируем матрицу значений с пустыми значениями 247 | data=pd.DataFrame(columns=cols,index=cols) 248 | 249 | #теперь заполняем матрицу, через итерацию по строкам 250 | for _, row in file_data.iterrows(): 251 | weight=row.Расстояние 252 | rw=row.Ячейка1 253 | cl=row.Ячейка2 254 | data[rw][cl]=weight 255 | data[cl][rw]=weight 256 | return data.fillna(0).astype(float).values,cols 257 | 258 | 259 | 260 | def route_cost(graph,result): 261 | first_id=result[0] 262 | cost=graph[result[-1]][first_id] 263 | for next_id in result[1:-1]: 264 | cost+=graph[first_id][next_id] 265 | first_id=next_id 266 | return cost 267 | 268 | 269 | 270 | def simulated_annealing(graph, min_cost, path, alpha,queue): 271 | random.seed() 272 | current_route_cost=min_cost 273 | lp=len(path) 274 | 275 | 276 | for temperature in np.logspace(0,10,num=lp**2,base=1e-1):#температура от 1 до 10-15 степени 277 | new_solution = path.copy() 278 | left_index = random.randint(2, lp- 1) 279 | right_index = random.randint(0, lp - left_index) 280 | last=right_index + left_index 281 | new_solution[right_index: last] = reversed(new_solution[right_index: last]) 282 | new_route_cost=route_cost(graph, new_solution) 283 | 284 | if new_route_cost < current_route_cost or np.exp((current_route_cost - new_route_cost) / temperature) > random.random(): 285 | cycled = cycle(new_solution) 286 | skipped = dropwhile(lambda x: x != 0, cycled) 287 | sliced = islice(skipped, None, lp) 288 | path = list(sliced) 289 | current_route_cost =route_cost(graph,path) 290 | 291 | #temperature*=alpha 292 | 293 | queue.put([path,current_route_cost]) 294 | 295 | 296 | def _start_new_proc(processes,iter_limit,graph, cost, best_path, alpha, queue): 297 | while(len(processes) <адрес файла для результата> -iter_limit<Количество одновременных процессов (больше - лучше, но дольше и идет нагрузка на процессор)>") 308 | 309 | rootDir = os.path.abspath(os.curdir) 310 | file=rootDir+'\\'+sys.argv[1] 311 | file_result=rootDir+'\\'+sys.argv[2] 312 | 313 | print('in: '+file) 314 | print('out: '+file_result) 315 | 316 | match = re.search(r'-iter_limit(\d+)', sys.argv[3]) 317 | if not match: 318 | raise ValueError("Нулевой iter_limit") 319 | iter_limit=int(match[1]) 320 | 321 | 322 | 323 | 324 | r = ReadData(file) 325 | graph=r.GetDistanceMat() 326 | # 327 | # ============================================================================= 328 | 329 | 330 | 331 | #начальный путь 332 | initial_path = christofides_tsp(graph) 333 | initial_min_cost=route_cost(graph, initial_path) 334 | total_lim=len(initial_path) 335 | print('initial cost: '+str(initial_min_cost)) 336 | 337 | queue = Queue() 338 | 339 | size=len(initial_path)#размер пути 340 | alpha=1-1e-3#параметр уменьшения температуры 341 | 342 | 343 | limit=iter_limit#минимальное количество не улучшений, чтобы выйти из основного цикла 344 | if limit<5: limit=5 345 | print('iter_limit: '+str(iter_limit)) 346 | 347 | 348 | pbar = tqdm.tqdm(desc='calculate',mininterval=2, maxinterval=5) 349 | 350 | best_path = initial_path.copy() 351 | min_cost=initial_min_cost 352 | 353 | 354 | #создаем процессы 355 | match_eqv=limit 356 | processes=_start_new_proc([],iter_limit,graph, initial_min_cost, initial_path, alpha, queue) 357 | while(processes): 358 | #проверяем какие процессы закончились 359 | for ind,el in enumerate(processes): 360 | p=el[0] 361 | if p.is_alive(): continue 362 | 363 | recent_cost=el[1] 364 | p.close() 365 | processes.pop(ind) 366 | total_lim-=1 367 | 368 | 369 | #выбераем лучший путь 370 | if not queue.empty(): 371 | path,cost = queue.get() 372 | if cost=0 and total_lim>=0: #новые процессы не создаем - вышли за лимиты итераций улучшения 384 | #запускаем новый процесс 385 | processes=_start_new_proc(processes,len(processes)+1,graph, cost, path, alpha, queue) 386 | break 387 | 388 | else: 389 | time.sleep(0.03) 390 | 391 | 392 | 393 | 394 | pbar.set_description(desc='Done.', refresh=True) 395 | pbar.close() 396 | print('final cost: '+str(min_cost)) 397 | 398 | 399 | #эмпирическая оценка улучшения маршрута 400 | upgrade_value=float(min_cost)/initial_min_cost 401 | print('upgrade_value (the less the better): '+str(upgrade_value)) 402 | 403 | 404 | 405 | queue.close() 406 | print('best cost: '+str(min_cost)) 407 | print('path: '+str(best_path)) 408 | -------------------------------------------------------------------------------- /бустинг имитации отжига 5.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Aug 23 12:19:37 2019 4 | 5 | @author: Belov 6 | """ 7 | #LICENSE ON christofides_tsp 8 | #======= 9 | #Copyright (c) 2016 D. S. Rahul 10 | #Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | #The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 12 | #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 13 | 14 | #Имитация отжига (С) 2019,2016 Белов С.В.,D. S. Rahul 15 | #mail@belovsergey.ru 16 | 17 | import pandas as pd 18 | import os 19 | import numpy as np 20 | from itertools import cycle, dropwhile, islice 21 | import random 22 | from multiprocessing import Process, Queue 23 | import tqdm 24 | import sys 25 | import re 26 | import io 27 | import json 28 | from pytsp.christofides_tsp import christofides_tsp 29 | import time 30 | #---------------------------------------------- 31 | 32 | 33 | def read_file(file): 34 | file_data=pd.read_csv(file , sep=';', header=0,encoding='utf-8')#читаем файл 35 | 36 | #Трансформируем в матрицу 37 | #Сначала получаем список уникальных ячеек 38 | cols=np.concatenate((file_data['Ячейка1'].unique(),file_data['Ячейка2'].unique()), axis=0) 39 | cols=np.unique(cols, axis=0) 40 | 41 | #теперь формируем матрицу значений с пустыми значениями 42 | data=pd.DataFrame(columns=cols,index=cols) 43 | 44 | #теперь заполняем матрицу, через итерацию по строкам 45 | for _, row in file_data.iterrows(): 46 | weight=row.Расстояние 47 | rw=row.Ячейка1 48 | cl=row.Ячейка2 49 | data[rw][cl]=weight 50 | data[cl][rw]=weight 51 | return data.fillna(0).astype(float).values,cols 52 | 53 | 54 | 55 | def route_cost(graph,result): 56 | first_id=result[0] 57 | cost=graph[result[-1]][first_id] 58 | for next_id in result[1:-1]: 59 | cost+=graph[first_id][next_id] 60 | first_id=next_id 61 | return cost 62 | 63 | 64 | 65 | def simulated_annealing(graph, min_cost, path, alpha,queue): 66 | random.seed() 67 | current_route_cost=min_cost 68 | lp=len(path) 69 | 70 | 71 | #temperature=1.0#начальная температура 72 | #while temperature>1e-15:#Пока температура не опустится до нуля 73 | for temperature in np.logspace(0,10,num=lp**2,base=1e-1):#температура от 1 до 10-15 степени 74 | new_solution = path.copy() 75 | left_index = random.randint(2, lp- 1) 76 | right_index = random.randint(0, lp - left_index) 77 | last=right_index + left_index 78 | new_solution[right_index: last] = reversed(new_solution[right_index: last]) 79 | new_route_cost=route_cost(graph, new_solution) 80 | 81 | if new_route_cost < current_route_cost or np.exp((current_route_cost - new_route_cost) / temperature) > random.random(): 82 | cycled = cycle(new_solution) 83 | skipped = dropwhile(lambda x: x != 0, cycled) 84 | sliced = islice(skipped, None, lp) 85 | path = list(sliced) 86 | current_route_cost =route_cost(graph,path) 87 | 88 | #temperature*=alpha 89 | 90 | queue.put([path,current_route_cost]) 91 | 92 | 93 | def _start_new_proc(processes,iter_limit,graph, cost, best_path, alpha, queue): 94 | while(len(processes) <адрес файла для результата> -iter_limit<Количество одновременных процессов (больше - лучше, но дольше и идет нагрузка на процессор)>") 106 | 107 | rootDir = os.path.abspath(os.curdir) 108 | file=rootDir+'\\'+sys.argv[1] 109 | file_result=rootDir+'\\'+sys.argv[2] 110 | 111 | print('in: '+file) 112 | print('out: '+file_result) 113 | 114 | match = re.search(r'-iter_limit(\d+)', sys.argv[3]) 115 | iter_limit=int(match[1]) 116 | 117 | 118 | graph,columns=read_file(file) 119 | 120 | #начальный путь 121 | initial_path = christofides_tsp(graph) 122 | initial_min_cost=route_cost(graph, initial_path) 123 | print('initial cost: '+str(initial_min_cost)) 124 | 125 | queue = Queue() 126 | 127 | size=len(initial_path)#размер пути 128 | alpha=1-1e-3#параметр уменьшения температуры 129 | iteration=size**2#количество итераций изменений 130 | total_lim=size#глобальный лимит итераций улучшения 131 | 132 | if not iter_limit: 133 | raise ValueError("Нулевой iter_limit") 134 | 135 | limit=iter_limit#минимальное количество не улучшений, чтобы выйти из основного цикла 136 | if limit<5: limit=5 137 | print('iter_limit: '+str(iter_limit)) 138 | 139 | pbar = tqdm.tqdm(desc='calculate',mininterval=2, maxinterval=5) 140 | 141 | best_path = initial_path.copy() 142 | min_cost=initial_min_cost 143 | 144 | 145 | #создаем процессы 146 | match_eqv=limit 147 | processes=_start_new_proc([],iter_limit,graph, initial_min_cost, initial_path, alpha, queue) 148 | while(processes): 149 | #проверяем какие процессы закончились 150 | for ind,el in enumerate(processes): 151 | p=el[0] 152 | if p.is_alive(): continue 153 | 154 | recent_cost=el[1] 155 | p.close() 156 | processes.pop(ind) 157 | total_lim-=1 158 | 159 | 160 | #выбераем лучший путь 161 | if not queue.empty(): 162 | path,cost = queue.get() 163 | if cost=0 and total_lim>=0: #новые процессы не создаем - вышли за лимиты итераций улучшения 175 | #запускаем новый процесс 176 | processes=_start_new_proc(processes,len(processes)+1,graph, cost, path, alpha, queue) 177 | break 178 | 179 | else: 180 | time.sleep(0.03) 181 | 182 | 183 | pbar.set_description(desc='Done.', refresh=True) 184 | pbar.close() 185 | print('final cost: '+str(min_cost)) 186 | 187 | 188 | #эмпирическая оценка улучшения маршрута 189 | upgrade_value=float(min_cost)/initial_min_cost 190 | print('upgrade_value (the less the better): '+str(upgrade_value)) 191 | 192 | 193 | 194 | queue.close() 195 | print('best cost: '+str(min_cost)) 196 | print('path: '+str(best_path)) 197 | 198 | 199 | #формируем путь с именами ячеек 200 | real_path = [int(columns[v]) for v in best_path] 201 | 202 | 203 | result={'path': real_path, 'cost':min_cost} 204 | with io.open(file_result, 'w', encoding='utf-8') as f: 205 | f.write(json.dumps(result, ensure_ascii=False)) -------------------------------------------------------------------------------- /неделя 6. Уменьшение количества цветов изображения.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Wed Mar 15 12:55:41 2017 4 | 5 | 6 | """ 7 | from skimage.io import imread 8 | import pylab 9 | from skimage import img_as_float 10 | import pandas as pd 11 | from sklearn.cluster import KMeans 12 | from math import log10 13 | #============================================================================== 14 | # Для работы с изображениями мы рекомендуем воспользоваться пакетом scikit-image. 15 | # Чтобы загрузить изображение, необходимо выполнить следующую команду 16 | #============================================================================== 17 | image = imread('parrots.jpg') 18 | #pylab.imshow(image)#Показ картинки 19 | 20 | #============================================================================== 21 | # Загрузите картинку parrots.jpg. Преобразуйте изображение, приведя все значения в интервал от 0 до 1. 22 | # Для этого можно воспользоваться функцией img_as_float из модуля skimage. Обратите внимание на этот шаг, 23 | # так как при работе с исходным изображением вы получите некорректный результат. 24 | #============================================================================== 25 | imgFloat=img_as_float(image) 26 | del image 27 | 28 | #Создайте матрицу объекты-признаки: характеризуйте каждый пиксель 29 | #тремя координатами - значениями интенсивности в пространстве RGB. 30 | imgMatrix={} 31 | 32 | index=0 33 | for x in range(len(imgFloat)): 34 | for y in range(len(imgFloat[x])): 35 | imgMatrix[index]=imgFloat[x][y] 36 | index+=1 37 | 38 | X_train=pd.DataFrame(imgMatrix).transpose() 39 | X_train.columns=['R','G','B'] 40 | del imgMatrix 41 | 42 | etalon=X_train.copy() 43 | #============================================================================== 44 | # Запустите алгоритм K-Means с параметрами init='k-means++' и random_state=241. 45 | # После выделения кластеров все пиксели, отнесенные в один кластер, попробуйте заполнить двумя способами: 46 | # медианным и средним цветом по кластеру. 47 | #============================================================================== 48 | def psnr(X,X_train_true):#Расчет PSNR по цветному изображению в float числах 49 | mse=0 50 | for col in X_train_true.columns: 51 | mse+=((X[col]-X_train_true[col])**2).sum() 52 | mse/=len(X_train_true)*3 53 | return 10*log10(1/mse)#в целочисленном формате в числителе было бы 255, в float - 1 54 | 55 | 56 | for clst in range(21): 57 | X_train=etalon.copy() 58 | maxClusters=clst+1 59 | 60 | cls=KMeans(init='k-means++',random_state=241,n_clusters=maxClusters)#обучаем кластеризатор 61 | kmeans = cls.fit(X_train) 62 | 63 | X_train['cluster']=kmeans.labels_#Добавляем классификацию кластера как колонку 64 | X_train.set_index('cluster', inplace=True)#Делаем новую колонку индексом 65 | X_train2=X_train.copy()#копируем данные 66 | X_train_true=X_train.copy()#копируем данные 67 | 68 | 69 | #замена цвета 70 | for cluster in range(maxClusters): 71 | for col in X_train.columns: 72 | median=X_train.loc[cluster,col].median()#считаем медиану интенсивности по кластеру 73 | X_train.loc[cluster,col]=median 74 | 75 | mean=X_train2.loc[cluster,col].mean()#считаем среднее интенсивности по кластеру 76 | X_train2.loc[cluster,col]=mean 77 | 78 | #============================================================================== 79 | # Измерьте качество получившейся сегментации с помощью метрики PSNR. 80 | # Эту метрику нужно реализовать самостоятельно (см. определение). 81 | # Найдите минимальное количество кластеров, при котором значение PSNR выше 20 82 | # (можно рассмотреть не более 20 кластеров, но не забудьте рассмотреть оба способа заполнения пикселей одного кластера). 83 | # Это число и будет ответом в данной задаче. 84 | #============================================================================== 85 | psnrMedian=psnr(X_train,X_train_true) 86 | psnrMean=psnr(X_train2,X_train_true) 87 | 88 | print("Clusters count %d, psnrMedian=%f, psnrMean=%f" % (maxClusters,psnrMedian,psnrMean)) 89 | if (psnrMedian>=20) | (psnrMean>=20): break 90 | --------------------------------------------------------------------------------