[toc]
Источник набора данных
2021 Китайский университет Студенческое страхование Digital Challenge-Digital Track(начиная с 26 апреля 2021 г.)
- Ссылка на конкурс:Woohoo.hey whit.com/org/safe/…
2021 China University Student Insurance Digital Challenge» спонсируется организационным комитетом конкурса, состоящим из единственной ежедневной рабочей группы, отвечающей за Комиссию по регулированию банковской и страховой деятельности Китая «Новости банковского дела и страхования Китая», Страхового общества Китая и China Ping An Property. Страхование, Шэньчжэнь Исследования больших данных Совместно организованный колледжем, Zhihu представляет собой комплексный проект мероприятий кампуса в качестве платформы для сотрудничества по содержанию.
Описание проблемы
На основе платформы анализа данных и моделирования, предоставленной официальным мероприятием, участникам необходимо в полной мере использовать информацию, содержащуюся в данных, и объединить бизнес-характеристики страхования, не связанного с автомобилем, для проведения обоснованной предварительной обработки данных и полной обработки и анализа данных для прогнозирования. каждое целевое (каридное) намерение приобрести товары, не связанные с автомобилем. (Финальный конкурс озаглавлен «Вопросы, связанные со страховым бизнесом», и его сложность увеличится. Конкретные подробности конкурса будут объявлены после завершения полуфинала.)
Результаты матча
После недели напряженной работы лучший результат — auc=0,90001787, рейтинг: (20/314).
предварительная обработка данных
предварительные данные
- Чтение обучающих и тестовых данных
df_train = pd.read_csv('/home/mw/input/pre8881/train.csv',index_col=0)
df_test = pd.read_csv('/home/mw/input/pretest_a3048/test_a.csv',index_col=0)
df_train.shape,df_test.shape
((684283, 65), (186925, 64))
Среди них 684 283 обучающих набора и 186 925 тестовых наборов. Содержит в общей сложности 65 измерений данных ylabel. Конкурсные вопросы не дают конкретных значений полей, что также усложняет понимание конкурсных вопросов.
Index(['dpt', 'xz', 'xb', 'carid', 'nprem_ly', 'ncd_ly', 'newvalue',
'bi_renewal_year', 'clmnum', 'regdate', 'trademark_cn', 'brand_cn',
'make_cn', 'series', 'capab', 'seats', 'use_type', 'change_owner',
'nprem_od', 'si_od', 'nprem_tp', 'si_tp', 'nprem_bt', 'si_bt',
'nprem_vld', 'si_vld', 'nprem_vlp', 'si_vlp', 'p1_prior_days_to_insure',
'suiche_nonauto_nprem_20', 'suiche_nonauto_nprem_19',
'suiche_nonauto_nprem_18', 'suiche_nonauto_nprem_17',
'suiche_nonauto_nprem_16', 'suiche_nonauto_amount_20',
'suiche_nonauto_amount_19', 'suiche_nonauto_amount_18',
'suiche_nonauto_amount_17', 'suiche_nonauto_amount_16',
'num_notcar_claim', 'p1_gender', 'p1_age', 'p1_census_register',
'p2_marital_status', 'f1_child_flag', 'f2_posses_house_flag',
'f2_cust_housing_price_total', 'p2_client_grade', 'w1_pc_wx_use_flag',
'p1_is_bank_eff', 'p2_is_enterprise_owner', 'p2_is_smeowner',
'active_7', 'active_30', 'active_90', 'active_365',
'p2_is_child_under_15_family', 'p2_is_adult_over_55_family',
'birth_month', 'p1_service_offer_cnt', 'p3_service_use_cnt',
'dur_personal_insurance_90', 'service_score_available',
'y1_is_purchase'],
dtype='object')
dtypes: float64(32), int64(9), object(23)
Из 65 полей 32 имеют тип float64, 9 — int64 и 23 — объектного типа.
Отсутствует заполнение значения
- Просмотрите 20 полей с наибольшим количеством отсутствующих значений.
df_train.isnull().sum().sort_values(ascending=False)[:20]
Если поле имеет числовой тип, отсутствующее значение будет заполнено режимом, а номинальный атрибут пока не будет заполнен.Использование lightgbm классифицирует нулевое значение номинального атрибута в одну категорию.
columns = df_train.columns
for i in tqdm (range(len(columns))):
# print(df_train[columns[i]].dtype)
if df_train[columns[i]].dtype!='object' and columns[i]!='y1_is_purchase' :
# print(columns[i])
df_train[columns[i]].fillna(df_train[columns[i]].mode()[0], inplace=True)
df_test[columns[i]].fillna(df_test[columns[i]].mode()[0], inplace=True)
Кодировка номинального атрибута
LabelEncoder используется для кодирования категориальных собственных значений, то есть для кодирования прерывистых значений или текста
# 其他类别变量,直接类别编码
no_features = ['client_no', 'carid','y1_is_purchase']
data = pd.concat([df_train, df_test], axis=0)
for col in df_train.select_dtypes(include=['object']).columns:
if col not in no_features:
lb = LabelEncoder()
lb.fit(data[col].astype(str))
df_train[col] = lb.transform(df_train[col].astype(str))
df_test[col] = lb.transform(df_test[col].astype(str))
features = [col for col in df_train.columns if col not in no_features]
features
Обработка данных даты
Сначала преобразуйте regdate в тип datetime, а затем получите данные года.
df_train['regdate'] = pd.to_datetime(df_train['regdate'])
df_test['regdate'] = pd.to_datetime(df_test['regdate'])
df_train['regdate'] = df_train['regdate'].dt.year
df_test['regdate'] = df_test['regdate'].dt.year
добавить свойства
Подсчитайте общее количество значений атрибутов поля ['dpt'], ['client_no'], ['trademark_cn'], ['brand_cn'], ['make_cn']
# 计数
for f in [['dpt'], ['client_no'], ['trademark_cn'], ['brand_cn'], ['make_cn'], ['series']]:
df_temp = df_feature.groupby(f).size().reset_index()
df_temp.columns = f + ['{}_count'.format('_'.join(f))]
df_feature = df_feature.merge(df_temp, how='left')
Подсчитайте среднюю стоимость покупок для разных атрибутов поля ['p1_census_register', 'dpt'] в обучающей выборке.
# 简单统计
def stat(df, df_merge, group_by, agg):
group = df.groupby(group_by).agg(agg)
columns = []
for on, methods in agg.items():
for method in methods:
columns.append('{}_{}_{}'.format('_'.join(group_by), on, method))
group.columns = columns
group.reset_index(inplace=True)
df_merge = df_merge.merge(group, on=group_by, how='left')
del (group)
gc.collect()
return df_merge
def statis_feat(df_know, df_unknow):
for f in tqdm(['p1_census_register', 'dpt']):
df_unknow = stat(df_know, df_unknow, [f], {
'y1_is_purchase': ['mean']})
return df_unknow
анализ данных
Анализ равновесия образца
fig = plt.figure()
plt.pie(df_train['y1_is_purchase'].value_counts(),
labels=df_train['y1_is_purchase'].value_counts().index,
autopct='%1.2f%%',counterclock = False)
plt.title('购买率')
plt.show()
# flag_0 = df_train['y1_is_purchase']==0
# n = sum(flag_0)
# flag_1 = df_train['y1_is_purchase']==1
# n,sum(flag_1)
# df_train[flag_0].shape
# df_train = pd.concat([df_train[flag_0][:n], df_train[flag_1][:n*1.5]])
# # df_train = df_train.reset_index()
# df_train['y1_is_purchase'].value_counts()
Очевидно, сбалансированы данные или нет, я сразу подумал о даунсэмплинге и оверсемплинге, но эффект не так хорош, как исходные данные.
анализ распределения данных
Проверьте распределение числовых полей с помощью диаграмм и удалите данные, которые значительно отклоняются.
columns = df_train.columns.tolist()
fig = plt.figure(figsize=(80,60),dpi=75)
j = 0
for i in range(len(columns)):
if not df_train[columns[i]].dtype=='object':
j+=1
plt.subplot(7,10,j+1)
sns.boxplot(df_train[columns[i]],orient='v',width=0.5)
plt.ylabel(columns[i],fontsize=36)
plt.show()
train_rows = len(df_train.columns)
plt.figure(figsize=(10*4,10*4))
columns = df_train.columns.tolist()
fig = plt.figure(figsize=(80,60),dpi=75)
j = 0
for i in range(len(columns)):
# print(df_train[columns[i]].dtype)
if df_train[columns[i]].dtype=='int64' and columns[i]!='y1_is_purchase':
# print(df_train[columns[i]].dtype)
df_train[columns[i]].fillna(df_train[columns[i]].mode(), inplace=True)
df_test[columns[i]].fillna(df_test[columns[i]].mode(), inplace=True)
j+=1
ax = plt.subplot(4,4,j)
sns.distplot(df_train[columns[i]],fit=stats.norm)
j+=1
ax = plt.subplot(4,4,j)
stats.probplot(df_train[columns[i]],plot=plt)
plt.tight_layout()
plt.show()
Применение модели
Древо решений
Дерево решений — это базовый метод классификации и регрессии. Модель дерева решений имеет высокую скорость классификации и легкую визуальную интерпретацию модели, но в то же время она также склонна к переоснащению, хотя и есть обрезка, но она неудовлетворительна.
В задаче классификации метод бустинга изучает несколько классификаторов, изменяя вес обучающих выборок (увеличивая вес неправильно классифицированных выборок и уменьшая вес отсоединенных выборок) и линейно комбинируя эти классификаторы для улучшения классификации. . Ускоряющее математическое представление:
где w - вес,представляет собой набор слабых классификаторов, и можно видеть, что конечный результат представляет собой линейную комбинацию базисных функций.
Следовательно, комбинация дерева решений и бустинга дает множество алгоритмов, в основном включающих бустинг-дерево, GBDT и т. д.
Повышение градиента — это метод повышения, основная идея которого заключается в том, что каждый раз при построении модели направление градиентного спуска функции потерь модели устанавливается заранее. Функция потерь предназначена для оценки производительности модели (как правило, степень соответствия + регулярный член), Считается, что чем меньше функция потерь, тем лучше производительность. И пусть функция потерь продолжает уменьшаться, чтобы модель можно было постоянно изменять для повышения производительности.Лучший способ - заставить функцию потерь уменьшаться в направлении градиента (разумно, направление градиента уменьшается быстрее всего).
lightgbm
Gradient Boost — это фреймворк, в который можно встроить множество различных алгоритмов.
- Алгоритм дерева решений на основе гистограммы.
Основная идея алгоритма гистограммы состоит в том, чтобы сначала разбить непрерывные собственные значения с плавающей запятой на k целых чисел, и в то же время построить гистограмму шириной k. При обходе данных статистика накапливается в гистограмме в соответствии с дискретизированным значением в виде индекса.После однократного обхода данных гистограмма накапливает требуемую статистику, а затем в соответствии с дискретным значением гистограммы она проходит, чтобы найти оптимальная точка сегментации.
- Односторонняя выборка на основе градиента (GOSS): использование GOSS может уменьшить большое количество экземпляров данных только с небольшими градиентами, так что при расчете прироста информации можно использовать только оставшиеся данные с высокими градиентами.По сравнению с XGBoost, просматривающим все собственные значения, это экономит много времени и места накладных расходов.
- Объединение эксклюзивных функций (EFB): с помощью EFB многие взаимоисключающие функции могут быть объединены в одну функцию, что позволяет достичь цели уменьшения размерности.
* Стратегия роста листьев по листам с ограничением по глубине: большинство инструментов GBDT используют неэффективную стратегию роста дерева решений по уровням, потому что они обрабатывают листья на одном уровне без разбора, что приводит к большому количеству ненужных накладных расходов. На самом деле коэффициент разделения многих листьев невелик, и нет необходимости искать и разделять. LightGBM использует листовой алгоритм с ограничениями по глубине.
- Прямая поддержка категориальной функции
- Поддерживает эффективный параллелизм
- Оптимизация коэффициента попаданий в кэш
```python
ycol = 'y1_is_purchase'
feature_names = features
model = lgb.LGBMClassifier(objective='binary',
boosting_type='gbdt',
num_leaves=64,
max_depth=10,
learning_rate=0.01,
n_estimators=10000,
subsample=0.8,
feature_fraction=0.6,
reg_alpha=10,
reg_lambda=12,
random_state=seed,
is_unbalance=True,
metric='auc')
df_oof = df_train[['carid', ycol]].copy()
df_oof['prob'] = 0
prediction = df_test[['carid']]
prediction['prob'] = 0
df_importance_list = []
kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=seed)
for fold_id, (trn_idx, val_idx) in enumerate(
kfold.split(df_train[feature_names], df_train[ycol])):
X_train = df_train.iloc[trn_idx][feature_names]
Y_train = df_train.iloc[trn_idx][ycol]
X_val = df_train.iloc[val_idx][feature_names]
Y_val = df_train.iloc[val_idx][ycol]
print('\nFold_{} Training ================================\n'.format(
fold_id + 1))
# print(df_oof.loc[val_idx]['prob'])
lgb_model = model.fit(X_train,
Y_train,
eval_names=['train', 'valid'],
eval_set=[(X_train, Y_train), (X_val, Y_val)],
verbose=100,
early_stopping_rounds=50)
pred_val = lgb_model.predict_proba(
X_val, num_iteration=lgb_model.best_iteration_)[:, 1]
# print(df_oof.iloc[val_idx])
df_oof.loc[val_idx, 'prob'] = pred_val
pred_test = lgb_model.predict_proba(
df_test[feature_names], num_iteration=lgb_model.best_iteration_)[:, 1]
prediction['prob'] += pred_test / kfold.n_splits
df_importance = pd.DataFrame({
'column': feature_names,
'importance': lgb_model.feature_importances_,
})
df_importance_list.append(df_importance)
del lgb_model, pred_val, pred_test, X_train, Y_train, X_val, Y_val
gc.collect()
Оценка модели
Пятикратная перекрестная проверка
Байесовская настройка
Байесовская оптимизация для настройки параметров машинного обучения была предложена Дж. Снуком (2012), основная идея заключается в том, что задана целевая функция оптимизации (обобщенная функция, достаточно указать вход и выход, не нужно знать внутреннюю структуру и математические свойства) , путем непрерывного добавления точек выборки для обновления апостериорного распределения целевой функции (процесс Гаусса) до тех пор, пока апостериорное распределение в основном не будет соответствовать реальному распределению. Проще говоря, информация о последнем параметре учитывается, чтобы лучше настроить текущие параметры.
Разница между ним и обычным поиском по сетке или случайным поиском заключается в следующем:
- Байесовская настройка параметров использует гауссовский процесс, учитывая предыдущую информацию о параметрах и постоянно обновляя предшествующую; поиск по сетке не учитывает предыдущую информацию о параметрах.
- Байесовская настройка параметров имеет мало итераций и высокую скорость; скорость поиска по сетке низкая, и при наличии большого количества параметров легко вызвать взрыв размерности.
- Байесовская настройка параметров по-прежнему надежна для невыпуклых задач; поиск по сетке позволяет легко получить локальный оптимум для невыпуклых задач.
параметры управления обучением | значение | использование |
---|---|---|
max_depth |
максимальная глубина дерева | Когда модель переоснащается, рассмотрите возможность сначала уменьшитьmax_depth
|
min_data_in_leaf |
Минимальное количество записей, которое может иметь лист | По умолчанию 20, используется при переоснащении |
feature_fraction |
Например, когда он равен 0,8, это означает, что 80% параметров выбираются случайным образом для построения дерева на каждой итерации. | Используется при прокачке случайного леса |
bagging_fraction |
Масштаб данных, используемых на каждой итерации | Используется для ускорения обучения и уменьшения переобучения |
early_stopping_round |
Если одна мера проверочных данных находится в самой последнейearly_stopping_round Нет улучшения в раунде, модель перестанет тренироваться |
Ускорьте анализ и сократите количество чрезмерных итераций |
lambda | Укажите регуляризацию | 0~1 |
min_gain_to_split |
минимальный выигрыш, описывающий разделение | Полезное разделение деревьев управления |
max_cat_group |
Найдите точки разделения на границах группы | Когда количество категорий велико, их легко переобучить при поиске точек сегментации. |
```python
# 设置几个参数
def lgb_cv(colsample_bytree, min_child_samples,reg_alpha,reg_lambda,min_split_gain,subsample_freq,
num_leaves, subsample, max_depth,learning_rate,min_child_weight):
model = lgb.LGBMClassifier(boosting_type='gbdt',objective='binary',
colsample_bytree=float(colsample_bytree), learning_rate=float(learning_rate),
min_child_samples=int(min_child_samples), min_child_weight=float(min_child_weight),
min_split_gain = float(min_split_gain),subsample_freq = int(subsample_freq),
n_estimators=8000, n_jobs=-1, num_leaves=int(num_leaves),
random_state=None, reg_alpha=float(reg_alpha), reg_lambda=float(reg_lambda),max_depth=int(max_depth),
subsample=float(subsample))
cv_score = cross_val_score(model, x, y, scoring="f1", cv=5).mean()
return cv_score
# 使用贝叶斯优化
lgb_bo = BayesianOptimization(
lgb_cv,
{
'learning_rate': (0.008, 0.01),
'max_depth': (3, 10),
'num_leaves': (31, 127),
'min_split_gain':(0.0,0.4),
'min_child_weight':(0.001,0.002),
'min_child_samples':(18,22),
'subsample':(0.6,1.0),
'subsample_freq':(3,5),
'colsample_bytree':(0.6,1.0),
'reg_alpha':(0,0.5),
'reg_lambda':(0,0.5)
},
)
lgb_bo.maximize(n_iter=1000)
lgb_bo.max
# 将优化好的参数带入进行使用
Визуализируйте процесс принятия решений
from IPython.display import Image
model = lgb.LGBMClassifier(num_leaves=64,
max_depth=10,
learning_rate=0.01,
boosting_type = 'goss',
n_estimators=10000,
subsample=0.8,
feature_fraction=0.8,
reg_alpha=0.5,
reg_lambda=0.5,
random_state=seed,
metric="f1")
X_train = df_train[feature_names]
Y_train = df_train[ycol]
lgb_model = model.fit(X_train,
Y_train,
eval_names=['valid'],
eval_set=[(X_val, Y_val)],
verbose=10,
eval_metric='auc',
early_stopping_rounds=50)
import matplotlib.pyplot as plt
fig2 = plt.figure(figsize=(200, 200))
ax = fig2.subplots()
lgb.plot_tree(lgb_model, tree_index=1, ax=ax)
plt.show()
ROC-кривая
Распределение важности каждого атрибута
Путем проверки важности каждого атрибута в процессе принятия решений ранжируются лучшие поля.Дальнейшая разработка функций
слияние моделей
Простым взвешенным способом результаты трех моделей объединяются, чтобы избежать проблемы переобучения модели.
w_lgb = 0.333
w_xgb = 0.333
w_cbt = 0.333
oof['prob'] = oof['prob_lgb'] ** w_lgb * oof['prob_xgb'] ** w_xgb * oof['prob_cbt'] ** w_cbt
auc = roc_auc_score(oof['y1_is_purchase'], oof['prob'])
sub['label'] = sub['prob_lgb'] ** w_lgb * sub['prob_xgb'] ** w_xgb * sub['prob_cbt'] ** w_cbt
sub.head()
Просмотр объединенного результата
Суммировать
Поскольку это был первый раз, когда я официально участвовал в соревновании, я чувствовал себя немного ошеломленным перед данными 60 Вт. Постепенно просматривайте то, чему учили в классе, просматривая материалы. От проектирования функций до выбора модели и оптимизации параметров. В начале я построил свою собственную базовую линию с деревом решений. Затем перейдите к дереву повышения градиента и, наконец, объедините три модели XGBoost, LightGBM и CatBoost. Также научился использовать байесовскую оптимизацию параметров во время этого эксперимента. Дизайн этого эксперимента может быть не идеальным, и действительно есть много проблем, которые мы исправим и улучшим в будущем. Хотя эксперимент подошел к концу, мне еще предстоит пройти долгий путь, и я буду продолжать совершенствоваться шаг за шагом.
использованная литература
LightGBM: A Highly Efficient Gradient Boosting Decision Tree
Biau G, Devroye L, Lugosi G. Consistency of Random Forests and Other Averaging Classifiers.[J]. Journal of Machine Learning Research, 2008, 9(1):2015-2033.
Модель дерева решений, визуализация моделей XGBoost, LightGBM и CatBoost Краткое изложение алгоритма LightGBM
Примечания по настройке LightGBM
Frazier P I. A tutorial on Bayesian optimization[J]. arXiv preprint arXiv:1807.02811, 2018.