关注我的公众号YueTan进行交流探讨
欢迎关注数据比赛方案仓库 https://github.com/hongyingyue/Competition-solutions
- https://www.kaggle.com/code/kimtaehun/lightgbm-baseline-with-aggregated-log-data/notebook
- https://www.kaggle.com/code/cdeotte/xgboost-baseline-0-680
- https://www.kaggle.com/code/pourchot/simple-xgb
通过学习以上baseline进行学习
- xgboost版本也很重要,从1.4升级到1.6后,能够提升0.08
背景
针对某个level_group的特征,其中把train_df[‘event_name’]长变宽数据,进行提取特征
# reference: https://www.kaggle.com/code/cdeotte/random-forest-baseline-0-664/notebook
def feature_engineer(train):
dfs = []
for c in count_var:
tmp = train.groupby(['session_id','level_group'])[c].agg('nunique')
tmp.name = tmp.name + '_nunique'
dfs.append(tmp)
for c in mean_var:
tmp = train.groupby(['session_id','level_group'])[c].agg('mean')
dfs.append(tmp)
for c in event_var:
tmp = train.groupby(['session_id','level_group'])[c].agg('sum')
tmp.name = tmp.name + '_sum'
dfs.append(tmp)
df = pd.concat(dfs,axis=1)
df = df.fillna(-1)
df = df.reset_index()
df = df.set_index('session_id')
return df
目标: 由于一个level_group有多个问题,因此针对每个level_group建立的特征分布用不同模型去拟合问题
train_x = df_tr.iloc[train_index]
train_x = train_x.loc[train_x.level_group == grp]
train_users = train_x.index.values
train_y = train_label.loc[train_label.q==t].set_index('session').loc[train_users]
阈值:针对预测提交为类别的任务,阈值非常关键
scores = []; thresholds = []
best_score = 0; best_threshold = 0
for threshold in np.arange(0.4,0.81,0.01):
print(f'{threshold:.02f}, ',end='')
preds = (oof.values.reshape((-1))>threshold).astype('int')
m = f1_score(true.values.reshape((-1)), preds, average='macro')
scores.append(m)
thresholds.append(threshold)
if m>best_score:
best_score = m
best_threshold = threshold
polars
https://www.kaggle.com/code/pourchot/simple-xgb
其中,最后一个baseline采用polars编写,在数据越来越大的今天,polars可以加速cpu大数据量的计算
特征
columns = [
pl.col("page").cast(pl.Float32),
(
(pl.col("elapsed_time") - pl.col("elapsed_time").shift(1))
.fill_null(0)
.clip(0, 1e9)
.over(["session_id", "level_group"])
.alias("elapsed_time_diff")
),
(
(pl.col("screen_coor_x") - pl.col("screen_coor_x").shift(1))
.abs()
.over(["session_id", "level_group"])
.alias("location_x_diff")
),
(
(pl.col("screen_coor_y") - pl.col("screen_coor_y").shift(1))
.abs()
.over(["session_id", "level_group"])
.alias("location_y_diff")
),
pl.col("fqid").fill_null("fqid_None"),
pl.col("text_fqid").fill_null("text_fqid_None")
]
特征解析
# 单特征
columns = [
pl.col("page").cast(pl.Float32),
(
(pl.col("elapsed_time") - pl.col("elapsed_time").shift(1))
.fill_null(0)
.clip(0, 1e9)
.over(["session_id", "level"])
.alias("elapsed_time_diff")
),
(
(pl.col("screen_coor_x") - pl.col("screen_coor_x").shift(1))
.abs()
.over(["session_id", "level"])
),
(
(pl.col("screen_coor_y") - pl.col("screen_coor_y").shift(1))
.abs()
.over(["session_id", "level"])
),
pl.col("fqid").fill_null("fqid_None"),
pl.col("text_fqid").fill_null("text_fqid_None")
]
group 特征
def feature_engineer(x, grp, use_extra, feature_suffix):
aggs = [
pl.col("index").count().alias(f"session_number_{feature_suffix}"), # session长度
*[pl.col(c).drop_nulls().n_unique().alias(f"{c}_unique_{feature_suffix}") for c in CATS], # 类别的nunique
*[pl.col(c).std().alias(f"{c}_std_{feature_suffix}") for c in NUMS], # 数量的统计
*[pl.col(c).mean().alias(f"{c}_mean_{feature_suffix}") for c in NUMS],
*[pl.col(c).min().alias(f"{c}_min_{feature_suffix}") for c in NUMS],
*[pl.col(c).max().alias(f"{c}_max_{feature_suffix}") for c in NUMS],
*[pl.col(c).sum().alias(f"{c}_sum_{feature_suffix}") for c in NUMS],
*[pl.col("fqid").filter(pl.col("fqid") == c).count().alias(f"{c}_fqid_counts{feature_suffix}") # fqid 精细展开的每一个count
for c in fqid_lists],
*[pl.col("elapsed_time_diff").filter(pl.col("fqid") == c).std().alias(f"{c}_ET_std_{feature_suffix}") for # fqid下的时间差的,std
c in fqid_lists],
*[pl.col("elapsed_time_diff").filter(pl.col("fqid") == c).mean().alias(f"{c}_ET_mean_{feature_suffix}") for
c in fqid_lists],
*[pl.col("elapsed_time_diff").filter(pl.col("fqid") == c).max().alias(f"{c}_ET_max_{feature_suffix}") for
c in fqid_lists],
*[pl.col("elapsed_time_diff").filter(pl.col("fqid") == c).min().alias(f"{c}_ET_min_{feature_suffix}") for
c in fqid_lists],
*[pl.col("elapsed_time_diff").filter(pl.col("fqid") == c).sum().alias(f"{c}_ET_sum_{feature_suffix}") for
c in fqid_lists],
*[pl.col("text_fqid").filter(pl.col("text_fqid") == c).count().alias(f"{c}_text_fqid_counts{feature_suffix}") for # text_fqid的精细展开的count
c in text_lists],
*[pl.col("elapsed_time_diff").filter(pl.col("text_fqid") == c).std().alias(f"{c}_ET_std_{feature_suffix}") for # text_fqid的每一个的耗时的std
c in text_lists],
*[pl.col("elapsed_time_diff").filter(pl.col("text_fqid") == c).mean().alias(f"{c}_ET_mean_{feature_suffix}") for
c in text_lists],
*[pl.col("elapsed_time_diff").filter(pl.col("text_fqid") == c).max().alias(f"{c}_ET_max_{feature_suffix}") for
c in text_lists],
*[pl.col("elapsed_time_diff").filter(pl.col("text_fqid") == c).min().alias(f"{c}_ET_min_{feature_suffix}") for
c in text_lists],
*[pl.col("elapsed_time_diff").filter(pl.col("text_fqid") == c).sum().alias(f"{c}_ET_sum_{feature_suffix}") for
c in text_lists],
*[pl.col("room_fqid").filter(pl.col("room_fqid") == c).count().alias(f"{c}_room_fqid_counts{feature_suffix}") # room_fqid的精细展开的count
for c in room_lists],
*[pl.col("elapsed_time_diff").filter(pl.col("room_fqid") == c).std().alias(f"{c}_ET_std_{feature_suffix}") for
c in room_lists],
*[pl.col("elapsed_time_diff").filter(pl.col("room_fqid") == c).mean().alias(f"{c}_ET_mean_{feature_suffix}") for
c in room_lists],
*[pl.col("elapsed_time_diff").filter(pl.col("room_fqid") == c).max().alias(f"{c}_ET_max_{feature_suffix}") for
c in room_lists],
*[pl.col("elapsed_time_diff").filter(pl.col("room_fqid") == c).min().alias(f"{c}_ET_min_{feature_suffix}") for
c in room_lists],
*[pl.col("elapsed_time_diff").filter(pl.col("room_fqid") == c).sum().alias(f"{c}_ET_sum_{feature_suffix}") for
c in room_lists],
*[pl.col("event_name").filter(pl.col("event_name") == c).count().alias(f"{c}_event_name_counts{feature_suffix}") # event
for c in event_name_feature],
*[pl.col("elapsed_time_diff").filter(pl.col("event_name") == c).std().alias(f"{c}_ET_std_{feature_suffix}")for
c in event_name_feature],
*[pl.col("elapsed_time_diff").filter(pl.col("event_name") == c).mean().alias(f"{c}_ET_mean_{feature_suffix}") for
c in event_name_feature],
*[pl.col("elapsed_time_diff").filter(pl.col("event_name") == c).max().alias(f"{c}_ET_max_{feature_suffix}") for
c in event_name_feature],
*[pl.col("elapsed_time_diff").filter(pl.col("event_name") == c).min().alias(f"{c}_ET_min_{feature_suffix}") for
c in event_name_feature],
*[pl.col("elapsed_time_diff").filter(pl.col("event_name") == c).sum().alias(f"{c}_ET_sum_{feature_suffix}") for
c in event_name_feature],
*[pl.col("name").filter(pl.col("name") == c).count().alias(f"{c}_name_counts{feature_suffix}") for c in # name
name_feature],
*[pl.col("elapsed_time_diff").filter(pl.col("name") == c).std().alias(f"{c}_ET_std_{feature_suffix}") for c in
name_feature],
*[pl.col("elapsed_time_diff").filter(pl.col("name") == c).mean().alias(f"{c}_ET_mean_{feature_suffix}") for c in
name_feature],
*[pl.col("elapsed_time_diff").filter(pl.col("name") == c).max().alias(f"{c}_ET_max_{feature_suffix}") for c in
name_feature],
*[pl.col("elapsed_time_diff").filter(pl.col("name") == c).min().alias(f"{c}_ET_min_{feature_suffix}") for c in
name_feature],
*[pl.col("elapsed_time_diff").filter(pl.col("name") == c).sum().alias(f"{c}_ET_sum_{feature_suffix}") for c in
name_feature],
*[pl.col("level").filter(pl.col("level") == c).count().alias(f"{c}_LEVEL_count{feature_suffix}") for c in LEVELS], # level
*[pl.col("elapsed_time_diff").filter(pl.col("level") == c).std().alias(f"{c}_ET_std_{feature_suffix}") for c in
LEVELS],
*[pl.col("elapsed_time_diff").filter(pl.col("level") == c).mean().alias(f"{c}_ET_mean_{feature_suffix}") for c in
LEVELS],
*[pl.col("elapsed_time_diff").filter(pl.col("level") == c).max().alias(f"{c}_ET_max_{feature_suffix}") for c in
LEVELS],
*[pl.col("elapsed_time_diff").filter(pl.col("level") == c).min().alias(f"{c}_ET_min_{feature_suffix}") for c in
LEVELS],
*[pl.col("elapsed_time_diff").filter(pl.col("level") == c).sum().alias(f"{c}_ET_sum_{feature_suffix}") for c in
LEVELS],
*[pl.col("level_group").filter(pl.col("level_group") == c).count().alias(f"{c}_LEVEL_group_count{feature_suffix}") for c in
level_groups],
*[pl.col("elapsed_time_diff").filter(pl.col("level_group") == c).std().alias(f"{c}_ET_std_{feature_suffix}") for c in
level_groups],
*[pl.col("elapsed_time_diff").filter(pl.col("level_group") == c).mean().alias(f"{c}_ET_mean_{feature_suffix}") for c in
level_groups],
*[pl.col("elapsed_time_diff").filter(pl.col("level_group") == c).max().alias(f"{c}_ET_max_{feature_suffix}") for c in
level_groups],
*[pl.col("elapsed_time_diff").filter(pl.col("level_group") == c).min().alias(f"{c}_ET_min_{feature_suffix}") for c in
level_groups],
*[pl.col("elapsed_time_diff").filter(pl.col("level_group") == c).sum().alias(f"{c}_ET_sum_{feature_suffix}") for c in
level_groups],
*[pl.col("index").filter((pl.col("level") == c) & (pl.col('room_fqid') == d)).count().alias(f"{c}{d}_level_room_count{feature_suffix}") for c in LEVELS for d in room_lists],
]
df = x.groupby(['session_id'], maintain_order=True).agg(aggs).sort("session_id")
if use_extra:
if grp == '5-12':
aggs = [
pl.col("elapsed_time").filter((pl.col("text")=="Here's the log book.")
|(pl.col("fqid")=='logbook.page.bingo'))
.apply(lambda s: s.max()-s.min()).alias("logbook_bingo_duration"),
pl.col("index").filter(
(pl.col("text") == "Here's the log book.") | (pl.col("fqid") == 'logbook.page.bingo')).apply(
lambda s: s.max() - s.min()).alias("logbook_bingo_indexCount"),
pl.col("elapsed_time").filter(
((pl.col("event_name") == 'navigate_click') & (pl.col("fqid") == 'reader')) | (
pl.col("fqid") == "reader.paper2.bingo")).apply(lambda s: s.max() - s.min()).alias(
"reader_bingo_duration"),
pl.col("index").filter(((pl.col("event_name") == 'navigate_click') & (pl.col("fqid") == 'reader')) | (
pl.col("fqid") == "reader.paper2.bingo")).apply(lambda s: s.max() - s.min()).alias(
"reader_bingo_indexCount"),
pl.col("elapsed_time").filter(
((pl.col("event_name") == 'navigate_click') & (pl.col("fqid") == 'journals')) | (
pl.col("fqid") == "journals.pic_2.bingo")).apply(lambda s: s.max() - s.min()).alias(
"journals_bingo_duration"),
pl.col("index").filter(((pl.col("event_name") == 'navigate_click') & (pl.col("fqid") == 'journals')) | (
pl.col("fqid") == "journals.pic_2.bingo")).apply(lambda s: s.max() - s.min()).alias(
"journals_bingo_indexCount"),
]
tmp = x.groupby(["session_id"], maintain_order=True).agg(aggs).sort("session_id")
df = df.join(tmp, on="session_id", how='left')
if grp == '13-22':
aggs = [
pl.col("elapsed_time").filter(
((pl.col("event_name") == 'navigate_click') & (pl.col("fqid") == 'reader_flag')) | (
pl.col("fqid") == "tunic.library.microfiche.reader_flag.paper2.bingo")).apply(
lambda s: s.max() - s.min() if s.len() > 0 else 0).alias("reader_flag_duration"),
pl.col("index").filter(
((pl.col("event_name") == 'navigate_click') & (pl.col("fqid") == 'reader_flag')) | (
pl.col("fqid") == "tunic.library.microfiche.reader_flag.paper2.bingo")).apply(
lambda s: s.max() - s.min() if s.len() > 0 else 0).alias("reader_flag_indexCount"),
pl.col("elapsed_time").filter(
((pl.col("event_name") == 'navigate_click') & (pl.col("fqid") == 'journals_flag')) | (
pl.col("fqid") == "journals_flag.pic_0.bingo")).apply(
lambda s: s.max() - s.min() if s.len() > 0 else 0).alias("journalsFlag_bingo_duration"),
pl.col("index").filter(
((pl.col("event_name") == 'navigate_click') & (pl.col("fqid") == 'journals_flag')) | (
pl.col("fqid") == "journals_flag.pic_0.bingo")).apply(
lambda s: s.max() - s.min() if s.len() > 0 else 0).alias("journalsFlag_bingo_indexCount")
]
tmp = x.groupby(["session_id"], maintain_order=True).agg(aggs).sort("session_id")
df = df.join(tmp, on="session_id", how='left')
return df.to_pandas()
时间特征
def time_feature(train):
train["year"] = train["session_id"].apply(lambda x: int(str(x)[:2])).astype(np.uint8)
train["month"] = train["session_id"].apply(lambda x: int(str(x)[2:4])+1).astype(np.uint8)
train["day"] = train["session_id"].apply(lambda x: int(str(x)[4:6])).astype(np.uint8)
train["hour"] = train["session_id"].apply(lambda x: int(str(x)[6:8])).astype(np.uint8)
train["minute"] = train["session_id"].apply(lambda x: int(str(x)[8:10])).astype(np.uint8)
train["second"] = train["session_id"].apply(lambda x: int(str(x)[10:12])).astype(np.uint8)
return train
base-nn
https://www.kaggle.com/code/abaojiang/lb-0-694-tconv-with-4-features-training-part
据称只使用4个特征
- Difference of elapsed_time
- event_name
- name
- room_fqid
业务过程
- https://www.kaggle.com/competitions/predict-student-performance-from-game-play/discussion/384796
结合上面的帖子,和某个用户行为来看游戏是如何进行的
尤其要注意区分几个level之间,以及理解下如何算答对答错的
一开始是: