Недавно я участвовал в конкурсе Kaggle, где мы должны предсказывать результаты выборов с помощью машинного обучения. Набор данных был взят с всеобщих выборов в Индии в 2019 году (см. Здесь). В этой статье объясняется, как очистить и подготовить набор данных, создать новые функции из существующих, а затем предсказать результаты с помощью популярного алгоритма машинного обучения. Здесь нет четкого объяснения большинства основных этапов предварительной обработки, визуализации данных и машинного обучения; Скорее я сосредоточился на разработке функций и их влиянии на производительность моделей. Если у вас нет четкого представления о том, что такое разработка функций, обратитесь к моей предыдущей статье Разработка основных функций для более эффективного машинного обучения.
Сначала мы должны загрузить набор данных в записную книжку. Большинство инженеров и экспертов по машинному обучению предпочитают использовать записные книжки для машинного обучения и задач инженерии данных на начальном этапе, потому что визуализировать данные и все другие шаги с помощью записной книжки действительно легко. Я предпочитаю использовать библиотеку pandas для загрузки набора данных, потому что она упрощает все этапы обработки данных без особых усилий. Ниже приведены библиотеки Python, которые я использовал в записной книжке.
import numpy as np import pandas as pd import os import matplotlib.pyplot as plt import seaborn as sns from sklearn.preprocessing import LabelEncoder from sklearn.preprocessing import MinMaxScaler from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsClassifier from sklearn.feature_selection import SelectKBest, chi2
Во-первых, давайте запустим приведенные ниже команды, чтобы получить общее представление о наборе данных и о том, как выглядят необработанные данные.
dataset = pd.read_csv('/kaggle/input/indian-candidates-for-general-election-2019/LS_2.0.csv') dataset.head()
dataset.info() <class 'pandas.core.frame.DataFrame'> RangeIndex: 2263 entries, 0 to 2262 Data columns (total 19 columns): STATE 2263 non-null object CONSTITUENCY 2263 non-null object NAME 2263 non-null object WINNER 2263 non-null int64 PARTY 2263 non-null object SYMBOL 2018 non-null object GENDER 2018 non-null object CRIMINAL CASES 2018 non-null object AGE 2018 non-null float64 CATEGORY 2018 non-null object EDUCATION 2018 non-null object ASSETS 2018 non-null object LIABILITIES 2018 non-null object GENERAL VOTES 2263 non-null int64 POSTAL VOTES 2263 non-null int64 TOTAL VOTES 2263 non-null int64 OVER TOTAL ELECTORS IN CONSTITUENCY 2263 non-null float64 OVER TOTAL VOTES POLLED IN CONSTITUENCY 2263 non-null float64 TOTAL ELECTORS 2263 non-null int64 dtypes: float64(3), int64(5), object(11) memory usage: 336.0+ KB
Как видно из приведенного выше анализа, набор данных содержит несколько числовых столбцов, и большинство столбцов не являются числовыми. Столбец WINNER содержит метку, указывающую, что кандидат выиграл или проиграл выборы. Также обратите внимание, что набор данных содержит некоторые значения «NaN», которые в основном отсутствуют. Некоторые имена столбцов содержат символы «\ n», что раздражает. Кроме того, значения столбцов ASSETS и LIABILITIES также содержат символы «\ n».
Рассматривая только доступные данные, мы можем рассматривать штат, округ, партию, пол, категорию и образование как категориальные характеристики. Кроме того, вы можете запустить команду dataset.describe (), чтобы получить статистическую сводку по числовым столбцам.
Затем мы должны очистить набор данных, исправить имена столбцов и обработать отсутствующие значения. Сначала я исправил неправильные имена столбцов и заменил все пробелы в именах столбцов символами подчеркивания (‘_’). Это не обязательный шаг, но меня раздражают неправильные названия столбцов.
# rename invalid column names dataset = dataset.rename(columns={'CRIMINAL\nCASES': 'CRIMINAL_CASES', 'GENERAL\nVOTES': 'GENERAL_VOTES', 'POSTAL\nVOTES': 'POSTAL_VOTES', 'TOTAL\nVOTES': 'TOTAL_VOTES', 'OVER TOTAL ELECTORS \nIN CONSTITUENCY': 'OVER_TOTAL_ELECTORS_IN_CONSTITUENCY', 'OVER TOTAL VOTES POLLED \nIN CONSTITUENCY': 'OVER_TOTAL_VOTES_POLLED_IN_CONSTITUENCY', 'TOTAL ELECTORS': 'TOTAL_ELECTORS'})
Затем давайте поищем недостающие значения в каждом столбце.
dataset.isna().sum() STATE 0 CONSTITUENCY 0 NAME 0 WINNER 0 PARTY 0 SYMBOL 245 GENDER 245 CRIMINAL_CASES 245 AGE 245 CATEGORY 245 EDUCATION 245 ASSETS 245 LIABILITIES 245 GENERAL_VOTES 0 POSTAL_VOTES 0 TOTAL_VOTES 0 OVER_TOTAL_ELECTORS_IN_CONSTITUENCY 0 OVER_TOTAL_VOTES_POLLED_IN_CONSTITUENCY 0 TOTAL_ELECTORS 0 dtype: int64
Вы можете видеть, что 10% значений строк отсутствуют. Существует несколько способов обработки пропущенных значений, таких как их удаление, использование обратного или прямого заполнения, вменение постоянного значения, среднее / медианное значение или вменение режима и т. Д. Однако я просто удаляю эти строки здесь для простоты (только 10% отсутствует), но всегда помните, что удаление значений сделает модель прогнозирования менее точной. Вам следует попытаться вменять недостающие значения в максимально возможной степени.
# drop rows with NA values dataset = dataset[dataset['GENDER'].notna()]
Давайте преобразуем столбцы ASSETS, LIABILITIES и CRIMINAL_CASES в числовые, потому что они представляют деньги и количество, а числовые значения будут иметь смысл для моделей. Для этого нам нужно удалить знак «Rs», символ «\ n» и запятые в каждом поле значения. Но также эти столбцы содержат значения «Nil» и «Not Available». Поэтому, прежде чем сделать их числовыми, мы должны заменить эти значения некоторым значимым значением (на данный момент я заменил их на 0).
# replace Nil values with 0 dataset['ASSETS'] = dataset['ASSETS'].replace(['Nil', '`', 'Not Available'], '0') dataset['LIABILITIES'] = dataset['LIABILITIES'].replace(['NIL', '`', 'Not Available'], '0') dataset['CRIMINAL_CASES'] = dataset['CRIMINAL_CASES'].replace(['Not Available'], '0') # clean ASSETS and LIABILITIES column values dataset['ASSETS'] = dataset['ASSETS'].map(lambda x: x.lstrip('Rs ').split('\n')[0].replace(',', '')) dataset['LIABILITIES'] = dataset['LIABILITIES'].map(lambda x: x.lstrip('Rs ').split('\n')[0].replace(',', '')) # convert ASSETS, LIABILITIES and CRIMINAL_CASES column values into numeric dataset['ASSETS'] = dataset['ASSETS'].astype(str).astype(float) dataset['LIABILITIES'] = dataset['LIABILITIES'].astype(str).astype(float) dataset['CRIMINAL_CASES'] = dataset['CRIMINAL_CASES'].astype(str).astype(int)
Теперь давайте сделаем нечисловые столбцы числовыми для повышения производительности. Обратите внимание, что некоторые типы моделей не могут работать с нечисловыми данными. Здесь я сосредоточусь на алгоритме классификации, который определенно не может обучаться на нечисловых данных. Поэтому я помечаю закодированные нечисловые столбцы с помощью sklearn LabelEncoder.
# label encode categorical columns lblEncoder_state = LabelEncoder() lblEncoder_state.fit(dataset['STATE']) dataset['STATE'] = lblEncoder_state.transform(dataset['STATE']) lblEncoder_cons = LabelEncoder() lblEncoder_cons.fit(dataset['CONSTITUENCY']) dataset['CONSTITUENCY'] = lblEncoder_cons.transform(dataset['CONSTITUENCY']) lblEncoder_name = LabelEncoder() lblEncoder_name.fit(dataset['NAME']) dataset['NAME'] = lblEncoder_name.transform(dataset['NAME']) lblEncoder_party = LabelEncoder() lblEncoder_party.fit(dataset['PARTY']) dataset['PARTY'] = lblEncoder_party.transform(dataset['PARTY']) lblEncoder_symbol = LabelEncoder() lblEncoder_symbol.fit(dataset['SYMBOL']) dataset['SYMBOL'] = lblEncoder_symbol.transform(dataset['SYMBOL']) lblEncoder_gender = LabelEncoder() lblEncoder_gender.fit(dataset['GENDER']) dataset['GENDER'] = lblEncoder_gender.transform(dataset['GENDER']) lblEncoder_category = LabelEncoder() lblEncoder_category.fit(dataset['CATEGORY']) dataset['CATEGORY'] = lblEncoder_category.transform(dataset['CATEGORY']) lblEncoder_edu = LabelEncoder() lblEncoder_edu.fit(dataset['EDUCATION']) dataset['EDUCATION'] = lblEncoder_edu.transform(dataset['EDUCATION'])
Теперь давайте обучим модель K-ближайших соседей и посмотрим на точность. KNN - это модель машинного обучения с учителем, которая подразделяется на алгоритмы классификации. Алгоритм работает, беря точку данных и находя k ближайших точек данных.
# separate train features and label y = dataset["WINNER"] X = dataset.drop(labels=["WINNER"], axis=1) # split dataset into train and test data X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1, stratify=y) # train and test knn model knn = KNeighborsClassifier() knn.fit(X_train, y_train) knn.predict(X_test) print("Testing Accuracy is: ", knn.score(X_test, y_test)*100, "%") Testing Accuracy is: 70.79207920792079 %
Модель достигла 70% точности без особого эффекта. Давайте нормализуем набор данных и посмотрим, насколько повысится точность. Я использовал MinMaxScaler из библиотеки scikit-learn, чтобы уменьшить все значения до диапазона 0–1.
# scaling values into 0-1 range scaler = MinMaxScaler(feature_range=(0, 1)) features = [ 'STATE', 'CONSTITUENCY', 'NAME', 'PARTY', 'SYMBOL', 'GENDER', 'CRIMINAL_CASES', 'AGE', 'CATEGORY', 'EDUCATION', 'ASSETS', 'LIABILITIES', 'GENERAL_VOTES', 'POSTAL_VOTES', 'TOTAL_VOTES', 'OVER_TOTAL_ELECTORS_IN_CONSTITUENCY', 'OVER_TOTAL_VOTES_POLLED_IN_CONSTITUENCY', 'TOTAL_ELECTORS'] dataset[features] = scaler.fit_transform(dataset[features])
Как вы можете видеть ниже, точность улучшилась за счет простой нормализации значений столбца. Однако мы могли бы еще больше повысить точность, применив несколько других методов проектирования функций.
Testing Accuracy is: 90.5940594059406 %
Более эффективное кодирование существующих функций
Если мы рассмотрим столбец ОБРАЗОВАНИЕ, он содержит 11 категориальных значений, которые может иметь конкретный кандидат.
Неграмотный, Грамотный, 5-й, 8-й, 10-й, 12-й, выпускник, аспирант, аспирант-специалист, докторская степень, другое
Если вдуматься, каждая из этих ценностей представляет определенный уровень образования. Путем кодирования меток мы просто присваиваем какое-то случайное целое число для каждого из этих значений, не задумываясь об их иерархическом уровне. Однако, если мы присвоим это целое число осмысленно в соответствии с образовательной квалификацией, можно надеяться, что модель будет работать лучше. Обратите внимание, что есть значение поля с именем «Другое», положение которого в иерархии нам неизвестно. Я просто присваиваю ему медианное значение из диапазона.
dataset['EDUCATION'].value_counts() Post Graduate 502 Graduate 441 Graduate Professional 336 12th Pass 256 10th Pass 196 8th Pass 78 Doctorate 73 Others 50 Literate 30 5th Pass 28 Not Available 22 Illiterate 5 Post Graduate\n 1 Name: EDUCATION, dtype: int64 # encode education column encoded_edu = [] # iterate through each row in the dataset for row in dataset.itertuples(): education = row.EDUCATION if education == "Illiterate": encoded_edu.append(0) elif education == "Literate": encoded_edu.append(1) elif education == "5th Pass": encoded_edu.append(2) elif education == "8th Pass": encoded_edu.append(3) elif education == "10th Pass": encoded_edu.append(4) elif education == "12th Pass": encoded_edu.append(7) elif education == "Graduate": encoded_edu.append(8) elif education == "Post Graduate": encoded_edu.append(9) elif education == "Graduate Professional": encoded_edu.append(10) elif education == "Doctorate": encoded_edu.append(11) else: encoded_edu.append(5) dataset['EDUCATION'] = encoded_edu
Давайте проанализируем столбец PARTY. Если мы перечислим количество кандидатов перед каждой партией, мы увидим, что только несколько партий имеют значительное количество кандидатов. Вся цель включения столбца ПАРТИЯ - оказать влияние партии кандидата на победу на выборах. Если у партии нет значительного числа кандидатов, влияние этой партии на победу кандидата невелико. Таким образом, мы можем закодировать их все в одну общую категорию (я закодировал их как «другие»).
dataset['PARTY'].value_counts() BJP 420 INC 413 IND 201 BSP 163 CPI(M) 100 ... AINRC 1 SKM 1 ANC 1 YKP 1 AJSUP 1 Name: PARTY, Length: 132, dtype: int64 # change party of the less frequent parties as Other # 'BJP','INC','IND','BSP', 'CPI(M)', 'AITC', 'MNM': high frequent # 'TDP', 'VSRCP', 'SP', 'DMK', 'BJD': medium frequent dataset.loc[~dataset["PARTY"].isin(['BJP','INC','IND','BSP', 'CPI(M)', 'AITC', 'MNM', 'TDP', 'VSRCP', 'SP', 'DMK', 'BJD']), "PARTY"] = "Other" dataset['PARTY'].value_counts()
Оба эти шага должны выполняться перед столбцами кодирования меток. Давайте еще раз обучим нашу модель и посмотрим на точность.
Testing Accuracy is: 92.07920792079209 %
Вы можете видеть, что точность немного улучшилась. До сих пор мы рассматривали только существующие функции. Однако мы можем сделать новые функции из существующих.
Создание новых функций
Чтобы создавать новые функции, мы должны иметь общее представление о доступных сырых функциях и о том, как они влияют на данный сценарий. Кроме того, требуется хорошее понимание предметной области. Итак, здесь мы должны подумать о том, какие факторы влияют на победу кандидата на выборах и какие соображения мы должны учитывать при голосовании за кандидата или партию. Для данного сценария я не знаю, какие страновые факторы учитываются перед голосованием за кандидата (какие специфические для страны факторы влияют на победу кандидата). Например, я понятия не имею, как КАТЕГОРИЯ влияет на результаты выборов. Но я придумал следующие особенности, исходя из общего варианта использования.
Набор данных содержит множество необработанных характеристик, которые напрямую повлияют на шансы кандидата на победу (например, штат, округ, партия, судимость, уровень образования, активы и т. Д.). Однако конкретный кандидат также может выиграть выборы в зависимости от статуса выдвинутой партии. Ниже приведены некоторые характеристики, которые могут отражать важность партии для вероятности победы кандидата.
1. Общее количество мест, выигранных партией
Мы можем рассмотреть партию кандидата, прежде чем голосовать за него. Если у партии высокий шанс на победу, кандидат от этой партии может иметь такой же шанс на победу (не всегда). Мы можем выделить этот сценарий, сделав функцию, представляющую количество мест, выигранных партией (вероятность выигрыша будет выделена подсчетом).
2. Количество мест, выигранных партией в избирательном округе
Могут быть партии, которые всегда будут побеждать в конкретном штате или округе. Я рассмотрел здесь избирательный округ, потому что это наименьшая доступная территория.
3. Уголовные дела против партии
Мы часто будем учитывать количество судимостей против партии перед голосованием. Если у партии больше уголовных дел (больше коррумпированных политиков), у этой партии может быть меньше шансов выиграть выборы (или наоборот ;-)). Мы можем выделить этот сценарий, сделав характеристику, представляющую количество судимостей против стороны.
4. Количество возбужденных по партии уголовных дел в каждом округе
Мы также можем разделить вышеупомянутый сценарий на подварианты, рассмотрев данные о судимости для каждого округа. Это может хорошо отражать указанную выше функцию.
5. Уровень образования кандидатов в партии
Мы также рассмотрим уровень образования кандидатов от партии, прежде чем голосовать за них. Если партия выдвинет большее количество образованных кандидатов, эта партия может выиграть выборы (более высокая вероятность). На более раннем этапе мы содержательно закодировали образовательные квалификации. Итак, если мы возьмем подсчет каждого кандидата в партии, эта характеристика будет отражать образовательный уровень партии.
6. Уровень образования кандидатов в партии по каждому округу
Как и в случае с уголовными делами, мы также можем учитывать уровень образования партии по каждому избирательному округу.
7. Количество кандидатов по округу от партии
Как я уже упоминал, у конкретной партии может быть больше шансов на победу в зависимости от избирательного округа. Если партия выдвигает большее количество кандидатов в округе, голоса будут разделены между кандидатами, и процентная доля каждого кандидата будет меньше. Это напрямую повлияет на вероятность выигрыша.
Ниже приведены еще несколько созданных мною функций, которые могут повлиять на вероятность победы кандидата.
1. Общее количество избирателей от каждого штата.
2. Общее количество избирателей в каждом округе.
3. Общее количество округов в каждом штате.
Итак, я создал в общей сложности 10 новых функций на основе существующих. Некоторые из этих функций могут не влиять на производительность модели.
# Preparing feature values cons_per_state = {} voters_per_state = {} party_winningSeats = {} party_criminal = {} party_education = {} party_totalCandidates_per_cons = {} party_winningSeats_per_cons = {} party_criminal_per_cons = {} party_education_per_cons = {} voters_per_cons = {} # group by state subset = dataset[['STATE', 'CONSTITUENCY', 'TOTAL_ELECTORS']] gk = subset.groupby('STATE') # for each state for name,group in gk: # total constituencies per state cons_per_state[name] = len(group) # total voters per state voters_per_state[name] = group['TOTAL_ELECTORS'].sum() # group by party subset = dataset[['PARTY', 'CONSTITUENCY', 'CRIMINAL_CASES', 'EDUCATION', 'WINNER']] gk = subset.groupby('PARTY') # for each party for name,group in gk: # winning seats by party party_winningSeats[name] = group[group['WINNER'] == 1.0].shape[0] # criminal cases by party party_criminal[name] = group['CRIMINAL_CASES'].sum() # education qualification by party (sum of candidates) party_education[name] = group['EDUCATION'].sum() # group by constituency gk2 = group.groupby('CONSTITUENCY') # for each constituency for name2, group2 in gk2: key = name2 + '_' + name # cons_party # total candidates by party in constituency party_totalCandidates_per_cons[key] = len(group2) # party winning seats in the constituency party_winningSeats_per_cons[key] = group2[group2['WINNER'] == 1.0].shape[0] # criminal cases by party in the constituency party_criminal_per_cons[key] = group2['CRIMINAL_CASES'].sum() # education qualification by party in constituency (sum of candidates) party_education_per_cons[key] = group2['EDUCATION'].sum() # Total voters per constituency subset = dataset[['CONSTITUENCY', 'TOTAL_ELECTORS']] gk = subset.groupby('CONSTITUENCY') # for each constituency for name,group in gk: voters_per_cons[name] = len(group) # Applying feature values # new feature columns total_cons_per_state = [] total_voters_per_state = [] total_voters_per_cons = [] winning_seats_by_party = [] criminal_by_party = [] education_by_party = [] total_candidates_by_party_per_cons = [] winning_seats_by_party_per_cons = [] criminal_by_party_per_cons = [] education_by_party_per_cons = [] # iterate through each row in the dataset for row in dataset.itertuples(): subkey = row.CONSTITUENCY + '_' + row.PARTY total_cons_per_state.append(cons_per_state.get(row.STATE)) total_voters_per_state.append(voters_per_state.get(row.STATE)) total_voters_per_cons.append(voters_per_cons.get(row.CONSTITUENCY)) winning_seats_by_party.append(party_winningSeats.get(row.PARTY)) criminal_by_party.append(party_criminal.get(row.PARTY)) education_by_party.append(party_education.get(row.PARTY)) total_candidates_by_party_per_cons.append(party_totalCandidates_per_cons.get(subkey)) winning_seats_by_party_per_cons.append(party_winningSeats_per_cons.get(subkey)) criminal_by_party_per_cons.append(party_criminal_per_cons.get(subkey)) education_by_party_per_cons.append(party_education_per_cons.get(subkey)) # append columns to dataset dataset['total_cons_per_state'] = total_cons_per_state dataset['total_voters_per_state'] = total_voters_per_state dataset['total_voters_per_cons'] = total_voters_per_cons dataset['winning_seats_by_party'] = winning_seats_by_party dataset['criminal_by_party'] = criminal_by_party dataset['education_by_party'] = education_by_party dataset['total_candidates_by_party_per_cons'] = total_candidates_by_party_per_cons dataset['winning_seats_by_party_per_cons'] = winning_seats_by_party_per_cons dataset['criminal_by_party_per_cons'] = criminal_by_party_per_cons dataset['education_by_party_per_cons'] = education_by_party_per_cons
Давайте еще раз обучим нашу модель и посмотрим, насколько повысится точность. Не нужно маркировать кодировку каких-либо созданных функций, поскольку все они числовые. Однако я нормализую их до диапазона 0–1 перед обучением модели.
Testing Accuracy is: 96.78217821782178 %
Важность функции
Удаление нерелевантных или менее важных функций повысит точность модели. На данный момент мы обучили нашу последнюю модель 28 функциям, в том числе недавно созданным 10. Однако некоторые из этих функций могут не сильно способствовать выводам на основе данных обучения. Удаление этих функций не снизит точность модели, но, надеюсь, повысит ее, потому что нерелевантные функции могут привести к неверным выводам для модели.
Во-первых, мы можем удалить некоторые функции, просто проанализировав их вклад. Столбец NAME не будет делать никаких полезных выводов для модели, потому что в идеале имя должно быть уникальным. Однако в некоторых случаях фамилия может иметь значение, потому что некоторые фамилии могут повлиять на победу на выборах. Также переменные PARTY и SYMBOL будут представлять одну и ту же функцию, и мы сможем удалить одну из них без какого-либо влияния на точность. Столбец TOTAL_VOTES содержит сумму столбца GENERAL_VOTES и столбца POSTAL_VOTES. Так что мы можем удалить и эти два. Если мы построим тепловую карту, представляющую корреляционную матрицу, мы увидим, что эти 3 функции будут сильно коррелированы.
# remove unnecessary columns X.drop(labels=["NAME"], axis=1, inplace=True) X.drop(labels=["SYMBOL"], axis=1, inplace=True) X.drop(labels=["POSTAL_VOTES"], axis=1, inplace=True) X.drop(labels=["GENERAL_VOTES"], axis=1, inplace=True)
Существует несколько способов выбора функций в зависимости от их важности. Я буду использовать метод одномерного выбора, чтобы определить наиболее важные функции и удалить другие. Я буду использовать SelectKBest из библиотеки Scikit learn с тестом хи-квадрат, чтобы оценить важность функции.
# apply SelectKBest class to extract top most features bestfeatures = SelectKBest(score_func=chi2, k=10) fit = bestfeatures.fit(X, y) dfscores = pd.DataFrame(fit.scores_) dfcolumns = pd.DataFrame(X.columns) # concat two dataframes for better visualization featureScores = pd.concat([dfcolumns, dfscores], axis=1) featureScores.columns = ['Specs', 'Score'] print(featureScores.nlargest(30, 'Score')) Specs Score 25 winning_seats_by_party_per_cons 486.207788 16 OVER_TOTAL_VOTES_POLLED_IN_CONSTITUENCY 285.347141 15 OVER_TOTAL_ELECTORS_IN_CONSTITUENCY 262.177373 14 TOTAL_VOTES 216.937788 12 GENERAL_VOTES 216.138799 21 winning_seats_by_party 199.662525 13 POSTAL_VOTES 65.126864 22 criminal_by_party 36.519437 3 PARTY 35.416433 23 education_by_party 6.576548 11 LIABILITIES 6.330339 24 total_candidates_by_party_per_cons 5.755538 20 total_voters_per_cons 5.302656 4 SYMBOL 4.128283 8 CATEGORY 4.047031 10 ASSETS 3.755575 7 AGE 2.077768 9 EDUCATION 0.888330 27 education_by_party_per_cons 0.840185 18 total_cons_per_state 0.481673 6 CRIMINAL_CASES 0.436667 19 total_voters_per_state 0.292948 26 criminal_by_party_per_cons 0.178720 5 GENDER 0.145870 1 CONSTITUENCY 0.143250 0 STATE 0.076833 17 TOTAL_ELECTORS 0.054486 2 NAME 0.003039
Давайте отбросим все столбцы с оценкой менее 3. Обратите внимание, что некоторые из функций, которые я создал ранее, также не важны для модели KNN.
X.drop(labels=["TOTAL_ELECTORS"], axis=1, inplace=True) X.drop(labels=["STATE"], axis=1, inplace=True) X.drop(labels=["CONSTITUENCY"], axis=1, inplace=True) X.drop(labels=["GENDER"], axis=1, inplace=True) X.drop(labels=["criminal_by_party_per_cons"], axis=1, inplace=True) X.drop(labels=["total_voters_per_state"], axis=1, inplace=True) X.drop(labels=["CRIMINAL_CASES"], axis=1, inplace=True) X.drop(labels=["total_cons_per_state"], axis=1, inplace=True) X.drop(labels=["EDUCATION"], axis=1, inplace=True) X.drop(labels=["education_by_party_per_cons"], axis=1, inplace=True) X.drop(labels=["AGE"], axis=1, inplace=True)
Теперь давайте снова обучим нашу модель наиболее важным функциям и оценим точность.
Testing Accuracy is: 99.5049504950495 %
Заключение
Как вы можете видеть из приведенных выше результатов, этапы разработки функций резко повысили производительность модели. Мы достигли точности 0,99, начиная с начальной точности 0,7. Сначала мы очищаем набор данных и преобразуем все значения в числовой формат. Затем мы создаем некоторые новые функции, используя существующие, и удаляем все менее важные функции. Наконец, мы уменьшаем значения до диапазона 0–1 и обучаем модель K-ближайших соседей. Обратите внимание, что мы могли бы еще больше повысить точность, применив перекрестную проверку. В заключение я хотел бы резюмировать точность после каждого важного шага, как показано ниже.
Feature Engineering Step Testing Accuracy Initially without any data processing 0.7079 Scale down values into 0-1 range 0.9059 Basic encoding of two columns 0.9208 Creating new features 0.9678 Removing unnecessary features 0.9950