Знакомство с проектом.
В этом проекте мы будем использовать несколько контролируемых алгоритмов для точного моделирования доходов людей с использованием данных, собранных в ходе переписи населения США 1994 года. Затем мы выберем лучший алгоритм-кандидат из предварительных результатов и далее оптимизируем этот алгоритм для наилучшего моделирования данных. Наша цель в этой реализации - построить модель, которая точно предсказывает, зарабатывает ли человек больше 50 000 долларов. Задачи такого рода могут возникать в некоммерческих организациях, где организации выживают за счет пожертвований. Понимание личного дохода может помочь некоммерческой организации лучше понять, какой размер пожертвования нужно запросить, и стоит ли им с самого начала обращаться к нему. Хотя может быть сложно определить общий уровень дохода человека непосредственно из общедоступных источников, мы можем (как мы увидим) вывести это значение из других общедоступных характеристик.
Набор данных для этого проекта происходит из Репозитория машинного обучения UCI. Набор данных был подарен Роном Кохави и Барри Беккером после публикации в статье Повышение точности наивно-байесовских классификаторов: гибрид дерева решений. Вы можете найти статью Рона Кохави онлайн. Данные, которые мы исследуем здесь, состоят из небольших изменений в исходном наборе данных, таких как удаление функции 'fnlwgt'
и записей с отсутствующими или плохо отформатированными записями. Этот проект я реализовал в рамках программы наноразмеров в udacity, и это мой первый проект в области науки о данных, и я хочу поделиться своим опытом, и я объясню это шаг за шагом как процесс науки о данных. также просто запомните первый шаг, или вы можете сказать, что вопрос, на который мы ищем здесь ответ, звучит так: Постройте модель, которая точно предсказывает, зарабатывает ли человек более 50 000 долларов. Это может быть больше вопросов, которые мы можем посмотреть к данным, но наша главная цель - получить ответ на поставленный выше вопрос. Так что пока, пожалуйста, загрузите данные и проанализируйте их, попытайтесь найти дополнительные вопросы, которые мы могли бы решить из набора данных. Давайте начнем, я начну с шага 2, поскольку мы уже обсуждали шаг 1 здесь.
Шаг 2. - Изучите данные.
Сначала мы импортируем данные и всю необходимую библиотеку.
# Import libraries necessary for this project import numpy as np import pandas as pd from time import time from IPython.display import display # Allows the use of display() for DataFrames # Import supplementary visualization code visuals.py import visuals as vs # Pretty display for notebooks %matplotlib inline # Load the Census dataset data = pd.read_csv("census.csv") # Success - Display the first record display(data.head(n=1))
Беглое исследование набора данных позволит определить, сколько человек входит в ту или иную группу, и расскажет нам о том, какой процент этих людей зарабатывает более 50 000 долларов. В ячейке кода ниже мы вычислим следующее:
- Общее количество записей,
'n_records'
- Число людей, зарабатывающих более 50 000 долларов в год,
'n_greater_50k'
. - Число людей, зарабатывающих не более 50 000 долларов в год,
'n_at_most_50k'
. - Процент людей, зарабатывающих более 50 000 долларов в год,
'greater_percent'
.
# TODO: Total number of records n_records = data.shape[0] # TODO: Number of records where individual's income is more than $50,000 n_greater_50k = data[data["income"] == ">50K"].shape[0] # TODO: Number of records where individual's income is at most $50,000 n_at_most_50k = data[data["income"] == "<=50K"].shape[0] # TODO: Percentage of individuals whose income is more than $50,000 greater_percent = float(n_greater_50k)*100/n_records # Print the results print("Total number of records: {}".format(n_records)) print("Individuals making more than $50,000: {}".format(n_greater_50k)) print("Individuals making at most $50,000: {}".format(n_at_most_50k)) print("Percentage of individuals making more than $50,000: {}%".format(greater_percent)) output:- Total number of records: 45222 Individuals making more than $50,000: 11208 Individuals making at most $50,000: 34014 Percentage of individuals making more than $50,000: 24.78439697492371%
** Исследование набора функций **
- возраст: постоянно.
- рабочий класс: частный, Self-emp-not-inc, Self-emp-inc, федеральное правительство, местное правительство, государственное правительство, без оплаты, никогда не работал.
- образование: бакалавриат, Some-College, 11-е, высшее образование, профессиональная школа, Assoc-acdm, доц., 9, 7-8, 12, магистратура, 1–4, 10, докторская степень. , 5-6-я, дошкольное учреждение.
- education-num: непрерывное.
- семейное положение: женат-гражданский супруг, разведен, не был в браке, разведен, вдовец, женат-супруг-отсутствует, женат-AF-супруг.
- род деятельности: техподдержка, ремесло-ремонт, другое-обслуживание, продажи, исполнительный менеджер, проф-специальность, хендлеры-уборщики, машинная поддержка, адм-канцелярия, сельское хозяйство-рыболовство, транспорт. -перемещение, Прив-хаус-серв, Защит-серв, Вооруженные Силы.
- отношения: жена, собственный ребенок, муж, не в семье, другой родственник, не состоящий в браке.
- раса: черный, белый, выходец из Азии, выходец из тихоокеанских островов, амер-индейец-эскимос, другой.
- пол: женский, мужской.
- прирост капитала: непрерывно.
- убыток капитала: непрерывно.
- часов в неделю: непрерывно.
- родная страна: США, Камбоджа, Англия, Пуэрто-Рико, Канада, Германия, окраины США (Гуам, Виргинские острова и т. д.), Индия,…. …… и т. д.
Шаг 3. - Подготовка данных
Прежде чем данные можно будет использовать в качестве входных для алгоритмов машинного обучения, их часто необходимо очистить, отформатировать и реструктурировать. Обычно это называется предварительной обработкой. К счастью, в этом наборе данных нет недопустимых или отсутствующих записей, с которыми мы должны иметь дело, однако есть некоторые особенности некоторых функций, которые необходимо настроить. Эта предварительная обработка может очень помочь с результатами и предсказательной силой почти всех алгоритмов обучения.
Преобразование перекошенных непрерывных элементов
Набор данных может иногда содержать по крайней мере одну функцию, значения которой обычно лежат около одного числа, но также будет иметь нетривиальное количество значительно больших или меньших значений, чем это единственное число. Алгоритмы могут быть чувствительны к такому распределению значений и могут работать хуже, если диапазон не нормализован должным образом. В наборе данных переписи этому описанию соответствуют две характеристики: ‘capital-gain'
и 'capital-loss'
.
# Split the data into features and target label income_raw = data['income'] features_raw = data.drop('income', axis = 1) # Visualize skewed continuous features of original data vs.distribution(data)
Для сильно искаженных распределений функций, таких как 'capital-gain'
и 'capital-loss'
, обычной практикой является применение логарифмического преобразования к данным, чтобы очень большие и очень маленькие значения не влияли отрицательно на производительность алгоритма обучения. Использование логарифмического преобразования значительно сокращает диапазон значений, вызванных выбросами. Однако следует соблюдать осторожность при применении этого преобразования: логарифм 0
не определен, поэтому мы должны перевести значения на небольшую величину выше 0
, чтобы успешно применить логарифм.
skewed = ['capital-gain', 'capital-loss'] features_log_transformed = pd.DataFrame(data = features_raw) features_log_transformed[skewed] = features_raw[skewed].apply(lambda x: np.log(x + 1)) # Visualize the new log distributions vs.distribution(features_log_transformed, transformed = True)
В дополнение к выполнению преобразований для объектов, которые сильно искажены, часто рекомендуется выполнить некоторый тип масштабирования для числовых объектов. Применение масштабирования к данным не меняет форму распределения каждой функции (например, 'capital-gain'
или 'capital-loss'
выше); однако нормализация гарантирует, что каждая функция обрабатывается одинаково при применении контролируемых учащихся. Обратите внимание, что после применения масштабирования наблюдение за данными в необработанной форме больше не будет иметь прежнего значения, как показано в примере ниже.
# Import sklearn.preprocessing.StandardScaler from sklearn.preprocessing import MinMaxScaler # Initialize a scaler, then apply it to the features scaler = MinMaxScaler() # default=(0, 1) numerical = ['age', 'education-num', 'capital-gain', 'capital-loss', 'hours-per-week'] features_log_minmax_transform = pd.DataFrame(data = features_log_transformed) features_log_minmax_transform[numerical] = scaler.fit_transform(features_log_transformed[numerical]) # Show an example of a record with scaling applied display(features_log_minmax_transform.head(n = 5))
Из таблицы в разделе Анализ данных выше мы видим, что для каждой записи есть несколько нечисловых функций. Обычно алгоритмы обучения ожидают, что ввод будет числовым, что требует преобразования нечисловых функций (называемых категориальными переменными). Одним из популярных способов преобразования категориальных переменных является использование схемы горячего кодирования. Быстрое кодирование создает «фиктивную» переменную для каждой возможной категории каждой нечисловой функции. Например, предположим, что someFeature
имеет три возможных записи: A
, B
или C
. Затем мы кодируем эту функцию в someFeature_A
, someFeature_B
и someFeature_C
.
| | someFeature | | someFeature_A | someFeature_B | someFeature_C | | : -: | : -: | | : -: | : -: | : -: | | 0 | B | | 0 | 1 | 0 | | 1 | C | - → горячее кодирование - → | 0 | 0 | 1 | | 2 | А | | 1 | 0 | 0 |
Кроме того, как и в случае с нечисловыми функциями, нам необходимо преобразовать нечисловую целевую метку 'income'
в числовые значения, чтобы алгоритм обучения работал. Поскольку для этой метки есть только две возможные категории ('‹= 50K' и '› 50K'), мы можем избежать использования однократного кодирования и просто закодировать эти две категории как 0
и 1
соответственно. В ячейке кода ниже вам нужно будет реализовать следующее:
# TODO: One-hot encode the 'features_log_minmax_transform' data using pandas.get_dummies() features_final = pd.get_dummies(features_log_minmax_transform) #display(features_final.head(n=5)) # TODO: Encode the 'income_raw' data to numerical values income = income_raw.apply(lambda x: 0 if x == "<=50K" else 1) # Print the number of features after one-hot encoding encoded = list(features_final.columns) print("{} total features after one-hot encoding.".format(len(encoded))) 103 total features after one-hot encoding.
Теперь все категориальные переменные преобразованы в числовые характеристики, а все числовые характеристики нормализованы. Как всегда, теперь мы разделим данные (как функции, так и их метки) на обучающие и тестовые наборы. 80% данных будет использовано для обучения и 20% для тестирования.
# Import train_test_split from sklearn.cross_validation import train_test_split # Split the 'features' and 'income' data into training and testing sets X_train, X_test, y_train, y_test = train_test_split(features_final,income, test_size = 0.2,random_state=0) # Show the results of the split print("Training set has {} samples.".format(X_train.shape[0])) print("Testing set has {} samples.".format(X_test.shape[0])) Training set has 36177 samples. Testing set has 9045 samples.
Этап 4. Внедрение - создание конвейера обучения и прогнозирования
Ниже представлены три модели, которые я решил использовать в этом проекте.
1: - RandomForestClassifier.
- Может обрабатывать большие наборы данных с большим количеством атрибутов
- Регрессия не так хороша с алгоритмами случайного леса
- так как это может обрабатывать большой атрибут, это может быть хорошим выбором
2: - Логистическая регрессия.
- Выходные данные имеют хорошую вероятностную интерпретацию, а также быстрое обучение и прогнозирование.
- Они недостаточно гибки, чтобы естественным образом фиксировать более сложные отношения.
- поскольку данные являются двоичными, это может быть хорошей моделью для использования здесь.
3: - GradientBoostingClassifier.
- очень хорошо подходит для больших наборов данных, снижает смещение и дисперсию, объединяет несколько слабых предикторов в один сильный предиктор.
- большое время обучения и некоторое время может быть переоснащено, если данных мало
- данные, которые у нас есть, достаточно большие и чистые, поэтому в этом случае подходит повышение градиента
Чтобы правильно оценить производительность каждой выбранной нами модели, важно создать конвейер обучения и прогнозирования, который позволит нам быстро и эффективно обучать модели с использованием обучающих данных различного размера и выполнять прогнозы на основе данных тестирования. Ваша реализация здесь будет использоваться в следующем разделе.
# TODO: Import two metrics from sklearn - fbeta_score and accuracy_score import warnings warnings.filterwarnings('ignore') from sklearn.metrics import fbeta_score, accuracy_score def train_predict(learner, sample_size, X_train, y_train, X_test,y_test): ''' inputs: - learner: the learning algorithm to be trained and predicted on - sample_size: the size of samples (number) to be drawn from training set - X_train: features training set - y_train: income training set - X_test: features testing set - y_test: income testing set ''' results = {} start = time() # Get start time learner.fit(X_train[:sample_size],y_train[:sample_size]) end = time() # Get end time # TODO: Calculate the training time results['train_time'] = end - start start = time() # Get start time predictions_test = learner.predict(X_test) predictions_train = learner.predict(X_train[:300]) end = time() # Get end time # TODO: Calculate the total prediction time results['pred_time'] = end - start results['acc_train'] = accuracy_score(y_train[:300],predictions_train) # TODO: Compute accuracy on test set using accuracy_score() results['acc_test'] = accuracy_score(y_test,predictions_test) results['f_train'] = fbeta_score(y_train[:300],predictions_train,beta=0.5) # TODO: Compute F-score on the test set which is y_test results['f_test'] = fbeta_score(y_test,predictions_test,beta=0.5) # Success print("{} trained on {} samples.".format(learner.__class__.__name__, sample_size)) # Return the results return results # TODO: Import the three supervised learning models from sklearn from sklearn.ensemble import RandomForestClassifier from sklearn.linear_model import LogisticRegression from sklearn.ensemble import GradientBoostingClassifier # TODO: Initialize the three models clf_A = RandomForestClassifier(random_state=80) clf_B = LogisticRegression(random_state=80) clf_C = GradientBoostingClassifier(random_state = 80) # TODO: Calculate the number of samples for 1%, 10%, and 100% of the training data # HINT: samples_100 is the entire training set i.e. len(y_train) # HINT: samples_10 is 10% of samples_100 (ensure to set the count of the values to be `int` and not `float`) # HINT: samples_1 is 1% of samples_100 (ensure to set the count of the values to be `int` and not `float`) samples_100 = len(y_train) samples_10 = int(len(y_train)*10/100) samples_1 = int(len(y_train)/100) # Collect results on the learners results = {} for clf in [clf_A, clf_B, clf_C]: clf_name = clf.__class__.__name__ results[clf_name] = {} for i, samples in enumerate([samples_1, samples_10, samples_100]): results[clf_name][i] = \ train_predict(clf, samples, X_train, y_train, X_test,y_test) # Run metrics visualization for the three supervised learning models chosen vs.evaluate(results, accuracy, fscore) RandomForestClassifier trained on 361 samples. RandomForestClassifier trained on 3617 samples. RandomForestClassifier trained on 36177 samples. LogisticRegression trained on 361 samples. LogisticRegression trained on 3617 samples. LogisticRegression trained on 36177 samples. GradientBoostingClassifier trained on 361 samples. GradientBoostingClassifier trained on 3617 samples. GradientBoostingClassifier trained on 36177 samples.
Шаг 5. - Улучшение результата и настройка модели
В этом заключительном разделе мы выберем из трех моделей контролируемого обучения лучшую модель для использования с данными учащихся. Затем вы выполните оптимизацию поиска по сетке для модели по всему обучающему набору (X_train
и y_train
), настроив по крайней мере один параметр, чтобы улучшить F-оценку ненастроенной модели.
Согласно приведенным выше метрикам производительности GradientBoostingClassifier имеет наибольшее количество баллов из трех, хотя на это уходит больше времени, но, тем не менее, на основе FSCORE GradientBoostingClassifier будет наиболее подходящей моделью для заданных данных.
Выполните точную настройку выбранной модели. Используйте поиск по сетке (GridSearchCV
) с хотя бы одним важным параметром, настроенным как минимум на 3 различных значения. Для этого потребуется использовать весь обучающий набор. В ячейке кода ниже вам нужно будет реализовать следующее:
- Импортируйте
sklearn.grid_search.GridSearchCV
иsklearn.metrics.make_scorer
. - Инициализируйте выбранный классификатор и сохраните его в
clf
. - Установите
random_state
, если он доступен для того же состояния, которое вы установили ранее. - Создайте словарь параметров, которые вы хотите настроить для выбранной модели.
- Пример:
parameters = {'parameter' : [list of values]}
. - Примечание. Избегайте настройки параметра
max_features
вашего учащегося, если этот параметр доступен! - Используйте
make_scorer
, чтобы создатьfbeta_score
оцениваемый объект (с 𝛽 = 0,5β = 0,5). - Выполните поиск по сетке на классификаторе
clf
с помощью'scorer'
и сохраните его вgrid_obj
. - Подгоните объект поиска по сетке к обучающим данным (
X_train
,y_train
) и сохраните его вgrid_fit
from sklearn.grid_search import GridSearchCV from sklearn.metrics import make_scorer, r2_score, fbeta_score # TODO: Initialize the classifier clf = GradientBoostingClassifier(random_state=80) # TODO: Create the parameters list you wish to tune, using a dictionary if needed. # HINT: parameters = {'parameter_1': [value1, value2], 'parameter_2': [value1, value2]} parameters = {'n_estimators': [200, 400, 600], 'learning_rate': [0.1, 0.5, 1] } # TODO: Make an fbeta_score scoring object using make_scorer() scorer = make_scorer(fbeta_score, beta=0.5) # TODO: Perform grid search on the classifier using 'scorer' as the scoring method using GridSearchCV() grid_obj = GridSearchCV(clf, parameters, scoring=scorer) # TODO: Fit the grid search object to the training data and find the optimal parameters using fit() grid_fit = grid_obj.fit(X_train, y_train) # Get the estimator best_clf = grid_fit.best_estimator_ # Make predictions using the unoptimized and model predictions = (clf.fit(X_train, y_train)).predict(X_test) best_predictions = best_clf.predict(X_test) # Report the before-and-afterscores print("Unoptimized model\n------") print("Accuracy score on testing data: {:.4f}".format(accuracy_score(y_test, predictions))) print("F-score on testing data: {:.4f}".format(fbeta_score(y_test, predictions, beta = 0.5))) print("\nOptimized Model\n------") print("Final accuracy score on the testing data: {:.4f}".format(accuracy_score(y_test, best_predictions))) print("Final F-score on the testing data: {:.4f}".format(fbeta_score(y_test, best_predictions, beta = 0.5))) Unoptimized model ------ Accuracy score on testing data: 0.8630 F-score on testing data: 0.7395 Optimized Model ------ Final accuracy score on the testing data: 0.8708 Final F-score on the testing data: 0.7531
Вывод :-
Как видите, оптимизируя модель, мы можем повысить точность и F-оценку. еще одна вещь, которую вы можете изучить в этом наборе данных, - это то, как конкретная функция влияет на производительность модели, и на основе этого вы можете уменьшить объем данных и увеличить время обучения. Кроме того, последним шагом в процессе анализа данных является развертывание обученной модели, чтобы ее можно было использовать в производственной среде. о котором я расскажу в другом блоге, если вы новичок, вы можете выполнить эти шаги и поэкспериментировать самостоятельно.
В случае более детального анализа вы можете проверить мой проект на github ссылка здесь.
Удачи …