Подход к прогнозному моделированию.

Введение

Многие некоммерческие компании ищут способы собрать средства для своего дела, и часто их усилия могут быть бесплодными просто потому, что они не обратились к нужному человеку или встретили не те перспективы.

Деловая потребность

Следовательно, необходимо отточить искусство поиска крупных потенциальных клиентов, доноров, которые могли бы внести щедрый вклад в дело. Прогнозное моделирование предлагает решение. Имея данные, вы можете предсказать потенциальных доноров, людей, которые могут внести значительный вклад в ваше дело, используя базовую демографическую информацию.

В этом проекте я использовал несколько контролируемых алгоритмов для точного моделирования доходов отдельных лиц с использованием данных, собранных в ходе переписи населения США 1994 года. Затем я выбрал лучший алгоритм-кандидат из предварительных результатов и дополнительно оптимизировал алгоритм для наилучшего моделирования данных. Цель этой реализации состояла в том, чтобы построить модель, которая точно предсказывает, зарабатывает ли человек больше 50 000 долларов.

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

Понимание данных

Набор данных для этого проекта происходит из Репозитория машинного обучения UCI. Набор данных был предоставлен Роном Кохави и Барри Беккером после публикации в статье Повышение точности наивно-байесовских классификаторов: гибрид дерева решений. Вы можете найти статью Рона Кохави онлайн.

Данные состоят из следующих функций

Резюме представленных записей

Подготовка данных

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

Обработка искаженных данных

Существуют некоторые функции, значения которых имеют тенденцию лежать около одного числа, но также имеют нетривиальное количество значительно больших меньших значений, чем это единственное число. Алгоритмы могут быть чувствительны к такому распределению значений и могут работать неэффективно, если диапазон не нормализован должным образом. . Характеристики, которые соответствуют этому описанию в нашем наборе данных, — это прирост капитала и убыток капитала.

Для сильно асимметричного распределения признаков, такого как выше, обычной практикой является применение к данным логарифмического преобразования, чтобы очень большие и очень маленькие значения не оказывали негативного влияния на производительность алгоритма обучения, по существу, логарифмическое преобразование уменьшает диапазон значений, вызванный выбросы. Следует соблюдать осторожность при применении этого преобразования. Логарифм 0 не определен, поэтому я перевел значения на небольшую величину выше 0, чтобы успешно применить логарифм.

# Log-transform the skewed features
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)

Замечено, что искаженные значения признаков были преобразованы в правильно распределенный диапазон значений с учетом нулевых значений, что гарантирует, что они не будут преобразованы в неопределенное значение.

Обработка числовых функций

Часто хорошей практикой является выполнение какого-либо масштабирования числовых признаков. Применение масштабирования данных не меняет форму каждой функции, однако нормализация гарантирует, что каждая функция обрабатывается одинаково при применении контролируемых учащихся. Это относится к таким значениям, как «образование-число», «прирост капитала», «потеря капитала».

# 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])

В приведенной выше таблице для каждой записи есть несколько нечисловых признаков, таких как рабочий класс, уровень образования, профессия, обычно алгоритмы обучения ожидают, что входные данные будут числовыми, что требует преобразования нечисловых признаков (называемых категориальной переменной). Один из способов сделать это — использовать схему горячего кодирования. Одно горячее кодирование создает фиктивную переменную для каждой возможной категории каждого нечислового признака.

# One-hot encode the 'features_log_minmax_transform' data using pandas.get_dummies()

features_final = pd.get_dummies(features_log_minmax_transform)

#Encode the 'income_raw' data to numerical values
income= income_raw.map({'<=50K':0,'>50K':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)))
display(features_final.head())

Обратите внимание, что функция рабочего класса была разделена на столбцы в зависимости от ее категорий.

Разделение данных

Теперь все категориальные переменные были преобразованы в числовые признаки, и все числовые признаки были нормализованы.

Затем я разделяю данные (как функции, так и их метки) на обучающие наборы и тестовые наборы. 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)

Моделирование

Из исследования некоммерческой организации известно, что люди, зарабатывающие более 50 000 долларов, чаще всего делают пожертвования на благотворительность. Поэтому организация заинтересована в точном прогнозировании людей, которые зарабатывают более 50 000 долларов.

Базовая модель

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

Оценка модели

Казалось бы, использование точности в качестве метрики для оценки модели было бы уместно, потому что идентификация кого-то, кто не зарабатывает более 50 000 долларов, как того, кто зарабатывает более 50 000 долларов, нанесла бы ущерб потребностям организации, поскольку они ищут людей, которые готовы пожертвовать.

Поэтому способность модели точно предсказывать тех, кто зарабатывает более 50 000 долларов, важнее, чем способность модели вспомнить этих людей.

При оценке моделей классификации оценка выполняется с использованием следующих показателей, приведенных ниже.

Точность: измеряет, как часто классификатор делает правильный прогноз. Это отношение количества правильных прогнозов к общему количеству прогнозов, т.е. количеству точек тестовых данных)

Точность: на примере классификатора спама в электронной почте. Это говорит нам о том, какая часть сообщений, которые мы классифицировали как спам, на самом деле были спамом. Это отношение истинных положительных результатов (слов, классифицированных как спам и являющихся спамом на самом деле) ко всем положительным результатам (всех слов, классифицированных как спам, независимо от того, была ли это правильная классификация). Другими словами, это отношение

[Истинно положительные результаты/(истинные положительные результаты + ложные положительные результаты)]

Отзыв (Чувствительность) показывает, какая часть сообщений, которые на самом деле были спамом, были классифицированы нами как спам. Это соотношение истинно положительных слов (слов, классифицированных как спам, и тех, которые действительно являются спамом. Другими словами, это соотношение

[Истинно положительные/(истинно положительные + ложноотрицательные)]

Оценка F-бета. Эта метрика математически учитывает как точность, так и отзыв при выводе значения оценки.

В частности, когда β = 0,5, больше внимания уделяется точности. Для простоты это называется сильной оценкой F 0,5 F-оценки.

Модель построения

В этом проекте я использовал модель наивного предиктора в качестве базовой модели. Здесь я предполагаю, что модель предсказывает 1 (т.е. человек зарабатывает более 50 тысяч) для каждой точки данных.

Подразумевается, что в нашей модели не было истинно отрицательных или ложноотрицательных результатов, поскольку мы не делаем никаких отрицательных прогнозов. Поэтому наша Точность становится такой же, как наша Точность (Истинно Положительные/(Истинно Положительные + Ложные Положительные)), поскольку каждый прогноз, который мы сделали со значением 1, который должен иметь 0, становится Ложным Положительным, поэтому наш знаменатель в этом случае - это общее число записей, которые у нас есть в общей сложности

Наш показатель отзыва (истинно положительные результаты/(истинно положительные результаты + ложноотрицательные результаты)) в этом параметре становится равным 1, поскольку у нас нет ложноотрицательных результатов.

Я оценил модель на основе показателей оценки, точности и F-оценки.

TP = np.sum(income) # Counting the ones as this is the naive case. Note that 'income' is the 'income_raw' data 
#encoded to numerical values done in the data preprocessing step.
FP = income.count() - TP # Specific to the naive case

TN = 0 # No predicted negatives in the naive case
FN = 0 # No predicted negatives in the naive case

#Calculate accuracy, precision and recall
accuracy = (TP+TN)/(TP+FP+TN+FN)
recall = TP/(TP+FN)
precision = TP/(TP+FP)

#Calculate F-score using the formula above for beta = 0.5 and correct values for precision and recall.
fscore = (1+0.5**2)*(precision*recall)/(((0.5**2)*precision)+recall)

# Print the results 
print("Naive Predictor: [Accuracy score: {:.4f}, F-score: {:.4f}]".format(accuracy, fscore))

Как видно выше, модель имеет точность 24,78% и F-показатель 0,2917. Эти значения являются индикаторами того, что наивный предиктор плохо предсказывает людей, которые зарабатывают более 50 000, однако этого было бы достаточно для базовой модели или отправной точки.

Теперь я рассмотрел некоторую модель контролируемого обучения для проекта. Ассортимент доступных вариантов модели включал:

  • Гауссовский наивный байесовский метод (GaussianNB)
  • Деревья решений
  • Методы ансамбля (бэггинг, AdaBoost, случайный лес, повышение градиента)
  • K-ближайшие соседи (KNeighbours)
  • Стохастический классификатор градиентного спуска (SGDC)
  • Методы опорных векторов (SVM)
  • Логистическая регрессия

Я выбрал 3 модели.

  • Модель ансамбля (модель случайного леса)
  • Гауссовская наивная байесовская модель
  • Машина опорных векторов

Модели ансамбля

Ансамблевые модели — очень полезные модели. Они сочетают в себе возможности двух моделей, максимально увеличивая потенциал каждой модели для достижения хорошей подгонки данных. Это означает, что одна модель обеспечит приемлемый уровень систематической ошибки, а другая — хороший уровень дисперсии. По сути, одна модель будет слабо соответствовать данным, а другая будет соответствовать им полностью. Модель ансамбля выбирает золотую середину между двумя моделями, но если ансамблей три или более, она использует систему голосования, которая выбирает наиболее предпочтительное соответствие.

Основным недостатком моделей Ensemble является то, что они могут требовать больших вычислительных ресурсов. для их работы требуется большое количество процессоров. Кроме того, найти правильную комбинацию модели для использования - это задача, это означает, что найти две модели с комбинацией правильного уровня смещения и дисперсии, модели, которая соответствовала бы структуре данных, но не слишком много, требует довольно много времени. и требовательна к власти. Однако это хороший выбор модели, которая дала бы хорошие прогнозы.

Ансамблевые модели включают Bagging, AdaBoost, Random Forest и Gradient Boosting. Однако для этого проекта я использовал случайный лес из вышеперечисленного.

Случайный лес

Случайный лес использует объединенную способность нескольких моделей дерева решений для прогнозирования, ансамбля деревьев. По сути, это то, что происходит: подмножества обучающих данных проходят через каждое дерево решений, модель соответствует данным, каждая модель выводит прогноз, прогноз из каждого дерева агрегируется, и выбирается прогноз с наибольшим количеством голосов.

Чтобы получить детализацию, каждое дерево решений берет подмножество обучающих данных и разбивает его на две оптимальные категории на основе определенных условий в узле дерева, дальнейшее разбиение выполняется в зависимости от количества ветвей и узлов, в основном оно ищет лучшую функцию. пары значений для создания узла и ветвей, после каждого разбиения задача выполняется рекурсивно, пока не будет достигнута максимальная глубина дерева или не будет найдено оптимальное дерево.

Для классификации он использует наиболее частый класс, предсказанный отдельными деревьями (большинство голосов), тогда как для задачи регрессии он использует среднее предсказание каждого дерева. Модель случайного леса может быть довольно медленной, так как на этапе обучения ей приходится выращивать много деревьев. существует также тенденция к переобучению модели, следовательно, необходимо проводить перекрестную проверку по мере ее развития.

Наивный байесовский метод Гаусса

Модель пытается предсказать, основываясь на вероятности исхода при наличии определенных признаков, синонимичных исходу. Модель рассматривает каждую функцию независимо, чтобы предсказать результат

При использовании Наивного Байеса для прогнозирования, зарабатывает ли человек больше или меньше 50 000 долларов. Модель сначала просматривает прошлые данные, отдельные характеристики, выбирает одну характеристику, например рабочий класс, она вычисляет вероятность того, что человек является вероятным донором (зарабатывает более 50 000 долларов США), учитывая, к какому рабочему классу он принадлежит, а также вычисляет, является ли человек также не является вероятным донором, учитывая рабочий класс. Это делается для других признаков, таких как брак, образование и т. д. Вероятность того, что человек является вероятным донором, учитывая совокупную вероятность всех признаков, сравнивается с вероятностью того, что человек не является вероятным донором, учитывая совокупную вероятность всех признаков. , наибольшая из обеих вероятностей определяет классификацию человека в качестве потенциального донора или нет.

Это может быть полезно, когда у вас нет большого количества обучающих данных и предположений о нормальном распределении данных. Модель довольно наивна, предполагая, что функции независимы, в некоторых случаях она может иметь тенденцию к переоснащению, что дает плохое обобщение набора данных и приводит к плохой производительности. Учитывая, что в наборе данных много независимых функций, ее применение может быть выполнено потребность. Также стоит отметить, что модель особенно более точна при работе с категориальной переменной, чем с непрерывной переменной.

Машина опорных векторов

Машина опорных векторов также является хорошим классификатором, который пытается найти центр минимального расстояния между ближайшими точками данных обоих классов, он пытается использовать гиперплоскость для классификации данных с учетом некоторых параметров C, gamma, rbf.

SVM — это тип линейного сепаратора. Предположим, мы хотим отделить черные круги от белых выше, нарисовав линию. Обратите внимание, что существует бесконечное количество строк, которые выполнят эту задачу. SVM, в частности, находят линию «максимальной маржи» — это линия «посередине». Интуитивно это работает хорошо, потому что допускает шум и наиболее терпимо к ошибкам с обеих сторон.

Это все (бинарные) SVM на самом деле. Мы проводим прямую линию через наши данные посередине, чтобы разделить их на два класса. Но что, если нам нужна не прямая линия, а изогнутая? Мы достигаем этого не рисуя кривые, а «поднимая» наблюдаемые особенности в более высокие измерения.

Классификатор SVM может быть очень эффективным, когда речь идет о выполнении нелинейной классификации, поскольку он может легко найти гиперплоскость, которая будет точно классифицировать данные. При использовании размеченных данных классификатор SVM не подходит, что вызывает некоторые ограничения в его применении.

Создание конвейера обучения и прогнозирования.

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

# Import two metrics from sklearn - fbeta_score and accuracy_score
from sklearn.metrics import fbeta_score
from sklearn.metrics import 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 = {}
    
    #Fit the learner to the training data using slicing with 'sample_size' using .fit(training_features[:], training_labels[:])
    start = time() # Get start time
    learner.fit(X_train[:sample_size], y_train[:sample_size])
    end = time() # Get end time
    
    # Calculate the training time
    results['train_time'] = end - start
        
    # Get the predictions on the test set(X_test),
    # then get predictions on the first 300 training samples(X_train) using .predict()
    start = time() # Get start time
    predictions_test = learner.predict(X_test)
    predictions_train = learner.predict(X_train[:300])
    end = time() # Get end time
    
    # Calculate the total prediction time
    results['pred_time'] = end - start
            
    # Compute accuracy on the first 300 training samples which is y_train[:300]
    results['acc_train'] = accuracy_score(y_train[:300], predictions_train)
        
    #Compute accuracy on test set using accuracy_score()
    results['acc_test'] = accuracy_score(y_test, predictions_test)
    
    #Compute F-score on the the first 300 training samples using fbeta_score()
    results['f_train'] = fbeta_score(y_train[:300], predictions_train, 0.5)
        
    #Compute F-score on the test set which is y_test
    results['f_test'] = fbeta_score(y_test,predictions_test,0.5)
    
    # Success
    print("{} trained on {} samples.".format(learner.__class__.__name__, sample_size))
        
    # Return the results
    return results

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

#Import the three supervised learning models from sklearn
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
from sklearn.naive_bayes import GaussianNB
#Initialize the three models
clf_A = RandomForestClassifier(n_estimators= 20, random_state = 0)
clf_B = SVC(C = 5, kernel = "rbf", degree = 3 )
clf_C = GaussianNB()

#Calculate the number of samples for 1%, 10%, and 100% of the training data
# Note: samples_100 is the entire training set i.e. len(y_train)
# Note: samples_10 is 10% of samples_100 (ensure to set the count of the values to be `int` and not `float`)
# Note: 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(0.1*len(y_train))
samples_1 = int(0.01*len(y_train))

# 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)

Выходные данные модели показывают время, необходимое для запуска, и производительность каждой модели при обучении на 1%, 10% и 100% данных.

Как видно на графиках слева, модели SVC потребовалось больше всего времени для обучения и прогнозирования со 100% набором данных.

На соседних графиках классификатор случайного леса имел самые высокие значения как точности, так и F-показателя для обучающих данных, имея точность около 95,6% на 100% данных, что говорит о способности модели классификатора случайного леса чтобы адекватно соответствовать набору данных, давая хорошие классификации по его свойствам. Это также дало относительно высокое значение точности и F-балла для данных тестирования для различных пропорций данных. И Random Forest, и SVC одинаково выполнялись на тестовом наборе.

Модель SVC показала высокие диапазоны точности на тренировочном наборе, в то время как F-оценка постоянно росла в пределах довольно высокой/средней отметки по мере увеличения процентной доли данных, используемых для обучения, особенно при 100% использовании данных. Подгонка гиперплоскости для классификации набора данных с учетом C-параметра, а также ядра для уменьшения допустимой погрешности является основным фактором, влияющим на точность и F-показатель модели.

Гауссовский наивный байесовский метод имел более низкую точность и F-показатель как на обучающем, так и на тестовом наборе, что может быть результатом того, что функции набора данных мало коррелируют друг с другом.

Для прогноза на тестовом наборе модели SVC потребовалось больше всего времени для обучения данным для всех различных процентов данных. RandomForest упал до того же значения, что и модель SVC, как по точности, так и по Fscore, что указывает на немного сниженную гибкость RandomForest Classfier, когда дело доходит до обобщения нового набора данных, оставляя гауссовский наивный байесовский метод по-прежнему довольно низкий.

Настройка модели

Модели можно точно настроить, чтобы улучшить или оптимизировать прогнозы. По сути, это касается выбора наиболее подходящих параметров модели, которые позволили бы модели адекватно соответствовать данным.

Поскольку Random Forest работал лучше всего, я выбрал его в качестве модели. Однако я считал, что он может работать лучше, если я точно настрою его параметры. Я использовал поиск по сетке (GridSearchCV), по крайней мере, с одним важным параметром, настроенным как минимум на 3 разных значения.

# Import 'GridSearchCV', 'make_scorer', and any other necessary libraries
from sklearn.grid_search import GridSearchCV 
from sklearn.metrics import make_scorer
from sklearn.ensemble import RandomForestClassifier
# Initialize the classifier
clf = RandomForestClassifier(n_estimators= 20, random_state = 0)

# 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": [10, 20, 35],"max_features": ['sqrt','log2', 'auto'],"min_samples_leaf":[50,80, 105]}

# Make an fbeta_score scoring object using make_scorer()
scorer = make_scorer(fbeta_score, beta=0.5)

# Perform grid search on the classifier using 'scorer' as the scoring method using GridSearchCV()
grid_obj = GridSearchCV(estimator=clf,param_grid = parameters, scoring =scorer)

# 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)))

Как видно выше, оптимизированная модель показала более высокую точность и F-показатель по сравнению с неоптимизированной моделью. Это показало, что метод GridSearch смог найти оптимальные параметры для RandomForest, которые дали бы хорошую классификацию.

Сравнение наивного предиктора с оптимизированной моделью показывает большую разницу в значениях, поскольку оптимизированная модель показывает улучшение стека в точности и F-оценке для предсказания донора.

В заключение, модель случайного леса дает наилучшую точность и F-показатель для тестовых данных среди других моделей. составляет более 50 000 долларов США, являются потенциальными донорами некоммерческой организации.