- 2023/11/29/用户新增预测挑战赛-特征工程/

任务2.3:特征工程

特征工程指的是把原始数据转变为模型训练数据的过程,目的是获取更好的训练数据特征。特征工程能使得模型的性能得到提升,有时甚至在简单的模型上也能取得不错的效果。

# 1. 导入需要用到的相关库
import pandas as pd
import numpy as np
import matplotlib as plt
import seaborn as sns

# 导入模型
from sklearn.linear_model import SGDClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.naive_bayes import MultinomialNB
from sklearn.ensemble import RandomForestClassifier

# 导入交叉验证和评价指标
from sklearn.model_selection import cross_val_predict
from sklearn.metrics import classification_report

# 2. 读取训练集和测试集文件
train_data = pd.read_csv('用户新增预测挑战赛公开数据/train.csv')
test_data = pd.read_csv('用户新增预测挑战赛公开数据/test.csv')

# 提取udmap特征,人工进行onehot
def udmap_onethot(d):
    v = np.zeros(9)
    if d == 'unknown':
        return v
    d = eval(d)
    for i in range(1, 10):
        if 'key' + str(i) in d:
            v[i-1] = d['key' + str(i)]
            
    return v
train_udmap_df = pd.DataFrame(np.vstack(train_data['udmap'].apply(udmap_onethot)))
test_udmap_df = pd.DataFrame(np.vstack(test_data['udmap'].apply(udmap_onethot)))
train_udmap_df.columns = ['key' + str(i) for i in range(1, 10)]
test_udmap_df.columns = ['key' + str(i) for i in range(1, 10)]

# 编码udmap是否为空
train_data['udmap_isunknown'] = (train_data['udmap'] == 'unknown').astype(int)
test_data['udmap_isunknown'] = (test_data['udmap'] == 'unknown').astype(int)

# udmap特征和原始数据拼接
train_data = pd.concat([train_data, train_udmap_df], axis=1)
test_data = pd.concat([test_data, test_udmap_df], axis=1)

# 提取eid的频次特征
train_data['eid_freq'] = train_data['eid'].map(train_data['eid'].value_counts())
test_data['eid_freq'] = test_data['eid'].map(train_data['eid'].value_counts())

# 提取eid的标签特征
train_data['eid_mean'] = train_data['eid'].map(train_data.groupby('eid')['target'].mean())
test_data['eid_mean'] = test_data['eid'].map(train_data.groupby('eid')['target'].mean())

# 提取时间戳
train_data['common_ts'] = pd.to_datetime(train_data['common_ts'], unit='ms')
test_data['common_ts'] = pd.to_datetime(test_data['common_ts'], unit='ms')
train_data['common_ts_hour'] = train_data['common_ts'].dt.hour
test_data['common_ts_hour'] = test_data['common_ts'].dt.hour
# 3. 进行特征工程
train_data['common_ts_day'] = train_data['common_ts'].dt.day
test_data['common_ts_day'] = test_data['common_ts'].dt.day

train_data['x1_freq'] = train_data['x1'].map(train_data['x1'].value_counts())
test_data['x1_freq'] = test_data['x1'].map(train_data['x1'].value_counts())
train_data['x1_mean'] = train_data['x1'].map(train_data.groupby('x1')['target'].mean())
test_data['x1_mean'] = test_data['x1'].map(train_data.groupby('x1')['target'].mean())

train_data['x2_freq'] = train_data['x2'].map(train_data['x2'].value_counts())
test_data['x2_freq'] = test_data['x2'].map(train_data['x2'].value_counts())
train_data['x2_mean'] = train_data['x2'].map(train_data.groupby('x2')['target'].mean())
test_data['x2_mean'] = test_data['x2'].map(train_data.groupby('x2')['target'].mean())

train_data['x3_freq'] = train_data['x3'].map(train_data['x3'].value_counts())
test_data['x3_freq'] = test_data['x3'].map(train_data['x3'].value_counts())

train_data['x4_freq'] = train_data['x4'].map(train_data['x4'].value_counts())
test_data['x4_freq'] = test_data['x4'].map(train_data['x4'].value_counts())

train_data['x6_freq'] = train_data['x6'].map(train_data['x6'].value_counts())
test_data['x6_freq'] = test_data['x6'].map(train_data['x6'].value_counts())
train_data['x6_mean'] = train_data['x6'].map(train_data.groupby('x6')['target'].mean())
test_data['x6_mean'] = test_data['x6'].map(train_data.groupby('x6')['target'].mean())

train_data['x7_freq'] = train_data['x7'].map(train_data['x7'].value_counts())
test_data['x7_freq'] = test_data['x7'].map(train_data['x7'].value_counts())
train_data['x7_mean'] = train_data['x7'].map(train_data.groupby('x7')['target'].mean())
test_data['x7_mean'] = test_data['x7'].map(train_data.groupby('x7')['target'].mean())

train_data['x8_freq'] = train_data['x8'].map(train_data['x8'].value_counts())
test_data['x8_freq'] = test_data['x8'].map(train_data['x8'].value_counts())
train_data['x8_mean'] = train_data['x8'].map(train_data.groupby('x8')['target'].mean())
test_data['x8_mean'] = test_data['x8'].map(train_data.groupby('x8')['target'].mean())
# 准备特征矩阵 X 和目标向量 y
X = train_data.drop(['udmap', 'common_ts', 'uuid', 'target'], axis=1)
y = train_data['target']

# 训练决策树模型
dt_model = DecisionTreeClassifier()
dt_model.fit(X, y)

# 获取特征重要性
feature_importance = dt_model.feature_importances_

# 创建一个包含特征名称和其重要性值的DataFrame
importance_df = pd.DataFrame({'Feature': X.columns, 'Importance': feature_importance})

# 按照重要性值降序排序
importance_df = importance_df.sort_values(by='Importance', ascending=False)

# 可视化特征重要性
sns.barplot(x='Importance', y='Feature', data=importance_df)
png
# 训练并验证DecisionTreeClassifier
pred = cross_val_predict(dt_model, X, y)
print(classification_report(y, pred, digits=3))
              precision    recall  f1-score   support

           0      0.955     0.951     0.953    533155
           1      0.707     0.726     0.717     87201

    accuracy                          0.919    620356
   macro avg      0.831     0.839     0.835    620356
weighted avg      0.920     0.919     0.920    620356

- 加入特征之后模型的精度有什么变化?

交叉验证f1-score从0.771提升到0.835。

- 思考并加入3个额外的特征,并观测模型精度的变化

Author: Siyuan
URL: https://siyuan-zou.github.io/2023/11/29/%E7%94%A8%E6%88%B7%E6%96%B0%E5%A2%9E%E9%A2%84%E6%B5%8B%E6%8C%91%E6%88%98%E8%B5%9B-%E7%89%B9%E5%BE%81%E5%B7%A5%E7%A8%8B/
This work is licensed under a CC BY-SA 4.0 .
- 2023/11/29/用户新增预测挑战赛-模型交叉验证/

任务2.2 模型交叉验证

# 导入库
import pandas as pd
import numpy as np
import matplotlib as plt
import seaborn as sns
# 读取训练集和测试集文件
train_data = pd.read_csv('用户新增预测挑战赛公开数据/train.csv')
test_data = pd.read_csv('用户新增预测挑战赛公开数据/test.csv')

# 提取udmap特征,人工进行onehot
def udmap_onethot(d):
    v = np.zeros(9)
    if d == 'unknown':
        return v
    d = eval(d)
    for i in range(1, 10):
        if 'key' + str(i) in d:
            v[i-1] = d['key' + str(i)]
            
    return v
train_udmap_df = pd.DataFrame(np.vstack(train_data['udmap'].apply(udmap_onethot)))
test_udmap_df = pd.DataFrame(np.vstack(test_data['udmap'].apply(udmap_onethot)))
train_udmap_df.columns = ['key' + str(i) for i in range(1, 10)]
test_udmap_df.columns = ['key' + str(i) for i in range(1, 10)]

# 编码udmap是否为空
train_data['udmap_isunknown'] = (train_data['udmap'] == 'unknown').astype(int)
test_data['udmap_isunknown'] = (test_data['udmap'] == 'unknown').astype(int)

# udmap特征和原始数据拼接
train_data = pd.concat([train_data, train_udmap_df], axis=1)
test_data = pd.concat([test_data, test_udmap_df], axis=1)

# 提取eid的频次特征
train_data['eid_freq'] = train_data['eid'].map(train_data['eid'].value_counts())
test_data['eid_freq'] = test_data['eid'].map(train_data['eid'].value_counts())

# 提取eid的标签特征
train_data['eid_mean'] = train_data['eid'].map(train_data.groupby('eid')['target'].mean())
test_data['eid_mean'] = test_data['eid'].map(train_data.groupby('eid')['target'].mean())

# 提取时间戳
train_data['common_ts'] = pd.to_datetime(train_data['common_ts'], unit='ms')
test_data['common_ts'] = pd.to_datetime(test_data['common_ts'], unit='ms')
train_data['common_ts_hour'] = train_data['common_ts'].dt.hour
test_data['common_ts_hour'] = test_data['common_ts'].dt.hour
# 导入模型
from sklearn.linear_model import SGDClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.naive_bayes import MultinomialNB
from sklearn.ensemble import RandomForestClassifier

# 导入交叉验证和评价指标
from sklearn.model_selection import cross_val_predict
from sklearn.metrics import classification_report

# 训练并验证SGDClassifier
pred = cross_val_predict(
    SGDClassifier(max_iter=1000, early_stopping=True),
    train_data.drop(['udmap', 'common_ts', 'uuid', 'target'], axis=1),
    train_data['target']
)
print(classification_report(train_data['target'], pred, digits=3))

# 训练并验证DecisionTreeClassifier
pred = cross_val_predict(
    DecisionTreeClassifier(),
    train_data.drop(['udmap', 'common_ts', 'uuid', 'target'], axis=1),
    train_data['target']
)
print(classification_report(train_data['target'], pred, digits=3))

# 训练并验证MultinomialNB
pred = cross_val_predict(
    MultinomialNB(),
    train_data.drop(['udmap', 'common_ts', 'uuid', 'target'], axis=1),
    train_data['target']
)
print(classification_report(train_data['target'], pred, digits=3))

# 训练并验证RandomForestClassifier
pred = cross_val_predict(
    RandomForestClassifier(n_estimators=5),
    train_data.drop(['udmap', 'common_ts', 'uuid', 'target'], axis=1),
    train_data['target']
)
print(classification_report(train_data['target'], pred, digits=3))
              precision    recall  f1-score   support

           0      0.862     0.781     0.820    533155
           1      0.151     0.238     0.185     87201

    accuracy                          0.704    620356
   macro avg      0.507     0.510     0.502    620356
weighted avg      0.762     0.704     0.730    620356

              precision    recall  f1-score   support

           0      0.934     0.940     0.937    533155
           1      0.618     0.593     0.605     87201

    accuracy                          0.891    620356
   macro avg      0.776     0.766     0.771    620356
weighted avg      0.889     0.891     0.890    620356

              precision    recall  f1-score   support

           0      0.893     0.736     0.807    533155
           1      0.221     0.458     0.298     87201

    accuracy                          0.697    620356
   macro avg      0.557     0.597     0.552    620356
weighted avg      0.798     0.697     0.735    620356

              precision    recall  f1-score   support

           0      0.921     0.955     0.937    533155
           1      0.642     0.498     0.561     87201

    accuracy                          0.890    620356
   macro avg      0.782     0.726     0.749    620356
weighted avg      0.882     0.890     0.885    620356

- 在上面模型中哪一个模型的macro F1效果最好,为什么这个模型效果最好?

树类模型效果都很好,决策树模型的效果最好。这是因为数据集非线性、较复杂、特征之间相关度不高,决策树更适合捕获复杂的决策边界。

- 使用树模型训练,然后对特征重要性进行可视化;

# 准备特征矩阵 X 和目标向量 y
X = train_data.drop(['udmap', 'common_ts', 'uuid', 'target'], axis=1)
y = train_data['target']
# 训练决策树模型
dt_model = DecisionTreeClassifier()
dt_model.fit(X, y)

# 获取特征重要性
feature_importance = dt_model.feature_importances_

# 创建一个包含特征名称和其重要性值的DataFrame
importance_df = pd.DataFrame({'Feature': X.columns, 'Importance': feature_importance})

# 按照重要性值降序排序
importance_df = importance_df.sort_values(by='Importance', ascending=False)

# 可视化特征重要性
sns.barplot(x='Importance', y='Feature', data=importance_df)
png

可以看出,对决策树模型来说,key6,key7,key8,x8均为重要性较低的特征。

# 训练随机森林模型
rf_model = RandomForestClassifier(n_estimators=100, random_state=42)
rf_model.fit(X, y)

# 获取特征重要性
feature_importance = rf_model.feature_importances_

# 创建一个包含特征名称和其重要性值的DataFrame
importance_df = pd.DataFrame({'Feature': X.columns, 'Importance': feature_importance})

# 按照重要性值降序排序
importance_df = importance_df.sort_values(by='Importance', ascending=False)

# 可视化特征重要性
sns.barplot(x='Importance', y='Feature', data=importance_df)
png

可以看出,对于随机森林模型来说,key7,key8和key9重要性最低。

-再加入3个模型训练,对比模型精度

可以随手一试。

Author: Siyuan
URL: https://siyuan-zou.github.io/2023/11/29/%E7%94%A8%E6%88%B7%E6%96%B0%E5%A2%9E%E9%A2%84%E6%B5%8B%E6%8C%91%E6%88%98%E8%B5%9B-%E6%A8%A1%E5%9E%8B%E4%BA%A4%E5%8F%89%E9%AA%8C%E8%AF%81/
This work is licensed under a CC BY-SA 4.0 .
- 2023/08/24/用户新增预测挑战赛-数据分析与可视化/

任务2.1 数据分析与可视化

# 导入库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# 读取训练集和测试集文件
train_data = pd.read_csv('用户新增预测挑战赛公开数据/train.csv')
test_data = pd.read_csv('用户新增预测挑战赛公开数据/test.csv')

# 相关性热力图
sns.heatmap(train_data.corr().abs(), cmap='YlOrRd')
png

通过分析相关性并画热力图,可以看出common_ts与x6, x7与x8具有显著相关性。

# x7分组下标签均值
sns.barplot(x='x7', y='target', data=train_data)
png

x7取值是离散的,说明是类别属性。

- 字段x1至x8为用户相关的属性,为匿名处理字段。添加代码对这些数据字段的取值分析,那些字段为数值类型?那些字段为类别类型?

fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(12, 6))
coordinates = [[0, 0], [0, 1], [1, 0], [1, 1]]
types = [1,2,6,8]

# x7分组下标签均值
for i in types:
    ax = axes[coordinates[types.index(i)][0],coordinates[types.index(i)][1]]  # Get the current Axes object
    
    sns.barplot(x=f'x{i}', y='target', data=train_data, ax=ax)  # Plot on the current Axes
    
    ax.set_title(f'x{i} vs Target')  # Set subplot title
    ax.set_xlabel(f'x{i}')  # Set x-axis label
    ax.set_ylabel('Target')  # Set y-axis label

# Adjust layout
plt.tight_layout()

# Show the plots
plt.show()
png

这说明x1,x2,x6,x8均为类别属性。

fig, axes = plt.subplots(nrows=3, ncols=1, figsize=(12, 6))
types = [3,4,5]

# x7分组下标签均值
for i in types:
    ax = axes[types.index(i)]  # Get the current Axes object
    
    sns.barplot(x=f'x{i}', y='target', data=train_data, ax=ax)  # Plot on the current Axes
    
    ax.set_title(f'x{i} vs Target')  # Set subplot title
    ax.set_xlabel(f'x{i}')  # Set x-axis label
    ax.set_ylabel('Target')  # Set y-axis label

# Adjust layout
plt.tight_layout()

# Show the plots
plt.show()
png

这说明x3,x4,x5都是数值属性。

- 对于数值类型的字段,考虑绘制在标签分组下的箱线图。

fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(12, 6))
types = [3,4,5]

# x7分组下标签均值
for i in types:
    ax = axes[types.index(i)]  # Get the current Axes object

    df = train_data[['target', f'x{i}']].groupby('target')
    df.boxplot(column=f'x{i}', subplots=False, ax=ax) # Plot on the current Axes

# Adjust layout
plt.tight_layout()

# Show the plots
plt.show()
png

注意到x4, x5的分布较为均匀正常,而x3有很多异常值,不适用箱线图。

df = train_data[['target', 'x3']].groupby('target')
for target_value, group_df in df:
    # target_value is the value of the 'target' column for the group
    # group_df is the DataFrame containing the data for that group
    print(f"Target: {target_value}")
    print(group_df)
Target: 0
        target  x3
0            0  41
1            0  41
2            0  41
3            0  41
4            0  41
...        ...  ..
620350       0  41
620351       0  41
620352       0  41
620354       0  41
620355       0  41

[533155 rows x 2 columns]
Target: 1
        target  x3
5            1  41
9            1  41
10           1  41
36           1  41
43           1  41
...        ...  ..
620326       1  41
620343       1  41
620346       1  41
620349       1  41
620353       1  41

[87201 rows x 2 columns]
# Assuming df is the grouped DataFrame as you mentioned: df = train_data[['target', 'x3']].groupby('target')
# Calculate the value counts for the 'x3' column in each group
value_counts_0 = df.get_group(0)['x3'].value_counts()
value_counts_1 = df.get_group(1)['x3'].value_counts()

# Plot the frequency distribution for each target group
plt.figure(figsize=(10, 5))

plt.subplot(1, 2, 1)  # Subplot for target 0
plt.bar(value_counts_0.index, value_counts_0.values)
plt.title("Frequency Distribution of x3 (Target 0)")
plt.xlabel("x3")
plt.ylabel("Frequency")

plt.subplot(1, 2, 2)  # Subplot for target 1
plt.bar(value_counts_1.index, value_counts_1.values)
plt.title("Frequency Distribution of x3 (Target 1)")
plt.xlabel("x3")
plt.ylabel("Frequency")

plt.tight_layout()
plt.show()
png
print(value_counts_0)
print(value_counts_1)
41    531017
47       478
15       265
7        238
71       133
       ...  
69         1
58         1
6          1
63         1
65         1
Name: x3, Length: 66, dtype: int64
41    86836
47       67
5        63
14       57
7        22
60       17
20       16
15       14
71       14
3        13
30        8
40        7
55        6
11        5
35        5
2         5
38        5
50        4
34        4
42        3
59        3
24        3
64        3
58        2
70        2
74        2
25        2
17        1
0         1
36        1
16        1
62        1
72        1
66        1
31        1
26        1
32        1
61        1
18        1
13        1
Name: x3, dtype: int64

这说明x3主要集中在取值41.

- 从common_ts中提取小时,绘制每小时下标签分布的变化。

train_data['common_ts'] = pd.to_datetime(train_data['common_ts'], unit='ms')
train_data['common_ts_hour'] = train_data['common_ts'].dt.hour
sns.barplot(x='common_ts_hour', y='target', data=train_data)
png

- 对udmap进行onehot,统计每个key对应的标签均值,绘制直方图。

def udmap_onethot(d):
    v = np.zeros(9)  # 创建一个长度为 9 的零数组
    if d == 'unknown':  # 如果 'udmap' 的值是 'unknown'
        return v  # 返回零数组
    d = eval(d)  # 将 'udmap' 的值解析为一个字典
    for i in range(1, 10):  # 遍历 'key1' 到 'key9', 注意, 这里不包括10本身
        if 'key' + str(i) in d:  # 如果当前键存在于字典中
            v[i-1] = d['key' + str(i)]  # 将字典中的值存储在对应的索引位置上
            
    return v  # 返回 One-Hot 编码后的数组

# 使用 apply() 方法将 udmap_onethot 函数应用于每个样本的 'udmap' 列
# np.vstack() 用于将结果堆叠成一个数组
train_udmap_df = pd.DataFrame(np.vstack(train_data['udmap'].apply(udmap_onethot)))

# 为新的特征 DataFrame 命名列名
train_udmap_df.columns = ['key' + str(i) for i in range(1, 10)]

# 将编码后的 udmap 特征与原始数据进行拼接,沿着列方向拼接
train_data = pd.concat([train_data, train_udmap_df], axis=1)

# 4. 编码 udmap 是否为空
# 使用比较运算符将每个样本的 'udmap' 列与字符串 'unknown' 进行比较,返回一个布尔值的 Series
# 使用 astype(int) 将布尔值转换为整数(0 或 1),以便进行后续的数值计算和分析
train_data['udmap_isunknown'] = (train_data['udmap'] == 'unknown').astype(int)
test_data['udmap_isunknown'] = (test_data['udmap'] == 'unknown').astype(int)
udmap_key = []
for i in range(1, 10):
    udmap_key.append(train_data[f'key{i}'].mean())
udmap_key
[64.21648698489254,
 260.31666333524623,
 29757.776829755818,
 1.4501092920839003,
 1.301670331229165,
 6.83070527245646,
 0.0005883718381058618,
 0.0001402420545622191,
 0.005659653489286797]
keylabel = ['key' + str(i) for  i in range(1, 10) ]
plt.bar(keylabel, udmap_key)
plt.title("udmap key mean")
plt.xlabel("udmap")
plt.ylabel("mean")
Text(0, 0.5, 'mean')
png
Author: Siyuan
URL: https://siyuan-zou.github.io/2023/08/24/%E7%94%A8%E6%88%B7%E6%96%B0%E5%A2%9E%E9%A2%84%E6%B5%8B%E6%8C%91%E6%88%98%E8%B5%9B-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%E4%B8%8E%E5%8F%AF%E8%A7%86%E5%8C%96/
This work is licensed under a CC BY-SA 4.0 .
- 2023/08/24/用户新增预测挑战赛/

1. 任务背景

为讯飞开放平台挑战赛的用户新增预测挑战赛提供的应用数据作为训练样本,基于提供的样本构建模型,预测用户的新增情况。

讯飞同时提供夏令营供学习,在此记录学习笔记。

1.1 数据说明

赛题数据由约62万条训练集、20万条测试集数据组成,共包含13个字段。其中uuid为样本唯一标识,eid为访问行为ID,udmap为行为属性,其中的key1到key9表示不同的行为属性,如项目名、项目id等相关字段,common_ts为应用访问记录发生时间(毫秒时间戳),其余字段x1至x8为用户相关的属性,为匿名处理字段。target字段为预测目标,即是否为新增用户。

1.2 评估指标

本次竞赛的评价标准采用f1_score,分数越高,效果越好。
f1_score 为二分类问题的一种常用评价标准,同时兼顾了分类模型的精确率(precision)和召回率(recall)。F1分数是模型精确率和召回率的一种调和平均,它的最大值是1,最小值是0。

  • 精确率(precision): 预测为True的样本中,多少个真的为True
  • 召回率(recall): 为True的样本中,多少个被预测为True

如下图:(待加入)

我们希望两个圆圈尽量重合,即精确率和召回率都尽量高,因此采用f1_score评价二分类问题。

2.1 任务一:一键跑通baseline

代码如下:

  1. 导入需要用到的相关库:
  • 导入 pandas 库,用于数据处理和分析
  • 导入 numpy 库,用于科学计算和多维数组操作
  • 从sklearn.tree模块中导入DecisionTreeClassifier,用于构建决策树分类模型
import pandas as pd
import numpy as np
from sklearn.tree import DecisionTreeClassifier
  1. 用pd读取训练集和测试集,转换成DataFrame格式
# 使用 read_csv() 函数从文件中读取训练集数据,文件名为 'train.csv'
train_data = pd.read_csv('用户新增预测挑战赛公开数据/train.csv')
# 使用 read_csv() 函数从文件中读取测试集数据,文件名为 'test.csv'
test_data = pd.read_csv('用户新增预测挑战赛公开数据/test.csv')
  1. 将 ‘udmap’ 列进行 One-Hot 编码

这种编码主要是对没有序关系的不同特征进行数学编码,由于不同特征之间不能比较、属于不同维度,因而有n个特征就采用n维向量编码,每个特征独享1个纬度。采用这样的编码的好处是避免机器按照数字大小比较不同特征:例如,将女性编译为1而男性编译为0,机器在处理时可能会默认女性特征比男性特征更重要。

# 数据样例:
#                    udmap  key1  key2  key3  key4  key5  key6  key7  key8  key9
# 0           {'key1': 2}     2     0     0     0     0     0     0     0     0
# 1           {'key2': 1}     0     1     0     0     0     0     0     0     0
# 2  {'key1': 3, 'key2': 2}   3     2     0     0     0     0     0     0     0

# 在 python 中, 形如 {'key1': 3, 'key2': 2} 格式的为字典类型对象, 通过key-value键值对的方式存储
# 而在本数据集中, udmap实际是以字符的形式存储, 所以处理时需要先用eval 函数将'udmap' 解析为字典

# 具体实现代码:
# 定义函数 udmap_onethot,用于将 'udmap' 列进行 One-Hot 编码
def udmap_onethot(d):
    v = np.zeros(9)  # 创建一个长度为 9 的零数组
    if d == 'unknown':  # 如果 'udmap' 的值是 'unknown'
        return v  # 返回零数组
    d = eval(d)  # 将 'udmap' 的值解析为一个字典
    for i in range(1, 10):  # 遍历 'key1' 到 'key9', 注意, 这里不包括10本身
        if 'key' + str(i) in d:  # 如果当前键存在于字典中
            v[i-1] = d['key' + str(i)]  # 将字典中的值存储在对应的索引位置上
            
    return v  # 返回 One-Hot 编码后的数组
# 使用 apply() 方法将 udmap_onethot 函数应用于每个样本的 'udmap' 列
# np.vstack() 用于将结果堆叠成一个数组
train_udmap_df = pd.DataFrame(np.vstack(train_data['udmap'].apply(udmap_onethot)))
test_udmap_df = pd.DataFrame(np.vstack(test_data['udmap'].apply(udmap_onethot)))
# 为新的特征 DataFrame 命名列名
train_udmap_df.columns = ['key' + str(i) for i in range(1, 10)]
test_udmap_df.columns = ['key' + str(i) for i in range(1, 10)]
# 将编码后的 udmap 特征与原始数据进行拼接,沿着列方向拼接
train_data = pd.concat([train_data, train_udmap_df], axis=1)
test_data = pd.concat([test_data, test_udmap_df], axis=1)
  1. 编码 udmap 是否为空

增加 ‘udmap_isunknown’ 特征列,取值0/1,以处理 ‘udmap’ 为 unknown 的情况。

# 使用比较运算符将每个样本的 'udmap' 列与字符串 'unknown' 进行比较,返回一个布尔值的 Series
# 使用 astype(int) 将布尔值转换为整数(0 或 1),以便进行后续的数值计算和分析
train_data['udmap_isunknown'] = (train_data['udmap'] == 'unknown').astype(int)
test_data['udmap_isunknown'] = (test_data['udmap'] == 'unknown').astype(int)
  1. 提取 eid 的频次特征
# 使用 map() 方法将每个样本的 eid 映射到训练数据中 eid 的频次计数
# train_data['eid'].value_counts() 返回每个 eid 出现的频次计数
train_data['eid_freq'] = train_data['eid'].map(train_data['eid'].value_counts())
test_data['eid_freq'] = test_data['eid'].map(train_data['eid'].value_counts())
  1. 提取 eid 的标签特征
# 使用 groupby() 方法按照 eid 进行分组,然后计算每个 eid 分组的目标值均值
# train_data.groupby('eid')['target'].mean() 返回每个 eid 分组的目标值均值
train_data['eid_mean'] = train_data['eid'].map(train_data.groupby('eid')['target'].mean())
test_data['eid_mean'] = test_data['eid'].map(train_data.groupby('eid')['target'].mean())

注意,在此我们使用了特征工程方法,即人为提取特征数据的频次、均值等特征,以改进模型拟合的效果。

  1. 提取时间戳

注意,需要注意时间戳的长度,如果是13位则 unit 为毫秒, 如果是10位则为秒。

# 使用 pd.to_datetime() 函数将时间戳列转换为 datetime 类型
# 样例:1678932546000->2023-03-15 15:14:16
train_data['common_ts'] = pd.to_datetime(train_data['common_ts'], unit='ms')
test_data['common_ts'] = pd.to_datetime(test_data['common_ts'], unit='ms')
# 使用 dt.hour 属性从 datetime 列中提取小时信息,并将提取的小时信息存储在新的列 'common_ts_hour'
train_data['common_ts_hour'] = train_data['common_ts'].dt.hour
test_data['common_ts_hour'] = test_data['common_ts'].dt.hour
  1. 加载决策树模型进行训练

直接使用sklearn中导入的包进行模型建立

clf = DecisionTreeClassifier()
# 使用 fit 方法训练模型
# train_data.drop(['udmap', 'common_ts', 'uuid', 'target'], axis=1) 从训练数据集中移除列 'udmap', 'common_ts', 'uuid', 'target'
# 这些列可能是特征或标签,取决于数据集的设置
# train_data['target'] 是训练数据集中的标签列,它包含了每个样本的目标值
clf.fit(
    train_data.drop(['udmap', 'common_ts', 'uuid', 'target'], axis=1),  # 特征数据:移除指定的列作为特征
    train_data['target']  # 目标数据:将 'target' 列作为模型的目标进行训练
)
  1. 对测试集进行预测,并保存结果到result_df中

    # 创建一个DataFrame来存储预测结果,其中包括两列:'uuid' 和 'target'
    # 'uuid' 列来自测试数据集中的 'uuid' 列,'target' 列将用来存储模型的预测结果
    result_df = pd.DataFrame({
        'uuid': test_data['uuid'],  # 使用测试数据集中的 'uuid' 列作为 'uuid' 列的值
        'target': clf.predict(test_data.drop(['udmap', 'common_ts', 'uuid'], axis=1))  # 使用模型 clf 对测试数据集进行预测,并将预测结果存储在 'target' 列中
    })
  2. 保存结果文件到本地

    # 将结果DataFrame保存为一个CSV文件,文件名为 'submit.csv'
    # 参数 index=None 表示不将DataFrame的索引写入文件中
    result_df.to_csv('submit.csv', index=None)
Author: Siyuan
URL: https://siyuan-zou.github.io/2023/08/24/%E7%94%A8%E6%88%B7%E6%96%B0%E5%A2%9E%E9%A2%84%E6%B5%8B%E6%8C%91%E6%88%98%E8%B5%9B/
This work is licensed under a CC BY-SA 4.0 .
- 2022/04/30/他祝大家周末愉快/

今天是五一节的第一天,前几天团购了火锅,从昨天晚上吃到今天晚上。我们三个姑娘肚子不够大,把所有的肉和家里的蘑菇蔬菜年糕土豆分了三顿吃,吃的很开心,有过节的感觉。是三个人一起准备,吃,然后收拾。一天没有学习,更有过节的感觉。

晚上是姚老师与夫人许老师组织的法语电影放映活动。没有什么人,我进去的时候只有我一个观众,吓了我一跳。然后许老师介绍了几分钟动画片的人物,中间姚老师提出了什么异议,许老师大声说:不对。他们非常可爱。然后姚老师开始放电影。我试图打毕业论文的tex,却被电影吸引进去。欧洲文化很有意思,他们天然的有种族观念,而中国人是没有的。所以我们的文化是混沌的,不是界限分明的。

中途跟妈妈讨论,我说:我觉得人只能做一些这种事情,看起来很小,没什么影响,但是只有爱可以拯救人类。如果非要打仗,那就一起毁灭算了。反正都是要死的。人类灭绝了地球上还会有新的生命。这很难,我看不到什么希望。但是我觉得拯救人类只有这一个办法。只有爱、共情、文学和艺术可以拯救人类。

放完电影,姚老师评论说:这个电影把现代的事情搬到古代,其实是给大人看的,不是给小孩看的对吧。然后他说:虽然现在周末只有一天了,但是祝大家周末愉快。

Author: Siyuan
URL: https://siyuan-zou.github.io/2022/04/30/%E4%BB%96%E7%A5%9D%E5%A4%A7%E5%AE%B6%E5%91%A8%E6%9C%AB%E6%84%89%E5%BF%AB/
This work is licensed under a CC BY-SA 4.0 .
- 2022/03/23/毕业/
申请优秀毕业生要求「总结过去,展望未来」,态度不端正不予申请,认真地想了想我都认识了什么人,收获了什么生活

在复旦大学的四年,第一年是在自然科学试验班度过的。我对于自己拥有一份转专业的经历感到很幸运:我在大一的寝室认识了我在大学关系最好的两个朋友。我和她们寒假去欧洲旅行,分别去对方家里住,一起解决情感问题。即使三个人专业不一样,也总是克服艰险到文图一起自习。转入数学系之后,我又认识了晓雯,在北区两个人住的时候,我们总是长谈、哈哈大笑、讨论完泛函互相夸对方真聪明。在数学系的每个学期都能因为讨论题目认识一些同学,但是大多数同学在选课不一样的大三失去了联系,只有孙进莫名其妙地成为了我的朋友。拓扑2和解析几何使我们相遇,从此以后数学系内部的许多消息都是他告诉我的,一起打过实力相当的篮球,也一起艰难地试过华波波老师的科研,最后只有他坚持了下去,找到了自己想做的方向。很多年以后回想起大学生活,理想可能会忘,但是和朋友度过的时光却会历久弥新。

为什么会转入数学系?说是喜欢数学,曾经也许有“数学系看起来很厉害”的因素,而我的数学不算差,稀里糊涂就转进来了。刚开始的分析课(一直到现在)令我痛苦,只有抽象代数不会。就像抓到光一样,硬着头皮学了下去。疫情的学期认识了姚一隽老师,姚老师对数学的态度我非常非常喜欢,我感到很荣幸成为他的学生。大三的时候迷茫,不知道该不该继续在数学上走下去,姚老师建议我去巴黎综合理工就读,为我开了一扇窗。而我去伯克利交换的时候感受到了好的数学,那段时光快乐非常,我的心要因我爱数学而高歌。

现在在做的事情是用大脑捡起以前学了就忘的东西,建立我的对数学的认识,并且试图不将数学分成分析几何代数的大块挑一块画地为牢,而是探索,努力建立Global Picture。就像Andrew Wiles说的那样,学数学就好像走入一个没有开灯的房间,刚开始漆黑一片,只能用手摸索家具都摆在什么位置,摸清楚之后,慢慢地灯就亮了。我现在刚进门,准备找一找沙发在哪里。

我在复旦的日子就是这样,朋友,爱,痛苦,数学;当然也不止这样,还可以说很多很多。作为我的大学,她已经给足了我丰富的四年;而我将要离开她,去做一个更自由的宇宙之游魂。

Author: Siyuan
URL: https://siyuan-zou.github.io/2022/03/23/%E6%AF%95%E4%B8%9A/
This work is licensed under a CC BY-SA 4.0 .
keyboard_arrow_up