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

Каждый раз, когда объявляется какое-либо соревнование, Kaggle отправляет уведомление по электронной почте. Так что всегда следите за ними. И вот так я наконец-то присоединился к своему первому соревнованию. Я выбрал Santander Value Prediction Challenge в первую очередь из-за небольшого набора данных. Поскольку у меня пока нет собственного графического процессора :(

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

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

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

Но что, если у вас нет каких-либо знаний в предметной области? Можно ли еще разрабатывать функции?

Трансформация функции

Целевой объект (который прогнозируется) должен иметь нормальное распределение. Это необходимо для того, чтобы ошибки в модели имели одинаковую дисперсию. То есть ошибка не должна колебаться в зависимости от значений зависимых характеристик. Можно сказать: если я увеличу свою переменную X на 1, то в среднем, при прочих равных условиях, Y должен увеличиться на β1. Итак, целевое распределение значений необходимо преобразовать в гауссовские распределения. Обычно этого можно достичь с помощью обратного логарифма или квадратного корня. Поскольку все значения в целевом объекте about были больше нуля, для нормализации данных применялось логарифмическое преобразование.

train = pd.read_csv("train.csv") 
y_train = train['target'] 
y_train = np.log1p(y_train)

Удаление функции

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

#Columns with all values same
cols_with_onlyone_val = train.columns[train.nunique() == 1]
train.drop(cols_with_onlyone_val.values, axis=1, inplace=True)
#Remove identical columns
NUM_OF_DECIMALS = 32
train = train.round(NUM_OF_DECIMALS)
colsToRemove = []
columns = train.columns
for i in range(len(columns)-1):
    v = train[columns[i]].values
    dupCols = []
    for j in range(i + 1,len(columns)):
        if np.array_equal(v, train[columns[j]].values):
            colsToRemove.append(columns[j])
train.drop(colsToRemove, axis=1, inplace=True)

Функция должна стабильно работать как с данными обучения, так и с данными тестирования. В этом можно убедиться, проверив распределение значений признаков. Итак, столбцы, которые не имеют одинакового распределения в данных обучения и тестирования, отбросьте их. Это было проверено с помощью теста K-S.

from scipy.stats import ks_2samp
THRESHOLD_P_VALUE = 0.01 #need tuned
THRESHOLD_STATISTIC = 0.3 #need tuned
diff_cols = [] 
for col in train.columns:
    statistic, pvalue = ks_2samp(train[col].values, test[col].values)
    if pvalue <= THRESHOLD_P_VALUE and np.abs(statistic) > THRESHOLD_STATISTIC:
        diff_cols.append(col)
for col in diff_cols:
    if col in train.columns:
        train.drop(col, axis=1, inplace=True)
        test.drop(col, axis=1, inplace=True)

Выбор функций

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

Итак, как работает дерево решений? У дерева решений есть корневой узел наверху. На основе внутреннего узла / условия дерево разделяется на две ветви. Одна ветвь удовлетворяет условию, а другая - нет. Конец ветви, которая больше не разделяется, - это листовой узел, который, наконец, предсказывает результат.

Итак, по каким критериям выбирается условие? Мера, на основе которой выбирается оптимальное условие, называется примесью. Для задач классификации это либо примесь Джини, либо получение информации, а для задач с деревом регрессии - дисперсия. Итак, выбрано условие, по которому дочерние узлы имеют минимальную примесь. Таким образом, в идеале в узле находится только один тип класса, который дает 100% точность. Чем меньше примесей в узле, тем выше точность и, следовательно, лучший прогноз. Таким образом, все функции ранжируются на основе их способности предоставлять более чистые дочерние узлы.

from sklearn import model_selection
from sklearn import ensemble
NUM_OF_FEATURES = 1000
def rmsle(y, pred):
    return np.sqrt(np.mean(np.power(y - pred, 2)))
x1, x2, y1, y2 = model_selection.train_test_split(
    train, y_train.values, test_size=0.20, random_state=5)
model = ensemble.RandomForestRegressor(n_jobs=-1, random_state=7)
model.fit(x1, y1)
print(rmsle(y2, model.predict(x2)))
col = pd.DataFrame({'importance': model.feature_importances_, 'feature': train.columns}).sort_values(
    by=['importance'], ascending=[False])[:NUM_OF_FEATURES]['feature'].values
train = train[col]
train.shape

Таким образом, с помощью описанных выше методов мы смогли значительно уменьшить количество функций и выбрать наиболее подходящие. Благодаря этому мы смогли получить оценку 1,07 и рейтинг 907/3736. А также с этим представлением я стал соавтором (на шаг ближе: D)

Первоначально опубликовано на vidishajitani.com 26 июля 2018 г.