Datawhale AI夏令营 机器学习组学习日记(任务2.1-2.2)

一、任务2.1

1.1任务内容

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

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

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

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

1.2代码解析

1.2.1字段x1至x8属性分析

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

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_data = pd.read_csv('train.csv')
test_data = pd.read_csv('test.csv')

        这段代码用于导入需要用到的包对udmap进行onehot的函数udmap_onethot()以及读取训练集和测试集。该函数已经在任务一的笔记中详细解释过。

Datawhale AI夏令营 机器学习组学习日记(任务1)_m0_49558200的博客-CSDN博客

# 查看字段的数据类型
data_types = train_data[['x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7', 'x8']].dtypes
plt.show()
# 打印数据类型
print(data_types)

        这段代码用于查看x1至x8字段的属性,使用.dtypes方法获取这些字段的数据类型,并将结果保存在data_types变量中,再将该字段输出。x1至x8字段的属性如下所示,可以发现他们都是数值型的。

 1.2.2字段x1至x8箱线图

numeric_fields = ['x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7', 'x8']

# 循环绘制箱线图
for field in numeric_fields:
    # 绘制每个数值类型字段在标签分组下的箱线图
    sns.boxplot(x='target', y=field, data=train_data)
    plt.title(f'Boxplot of {field}')
    plt.show()

        该段代码用于绘制每个数值类型字段在标签分组下的箱线图。通过for语句遍历numeric_fields列表中的字段名,使用sns.boxplot()函数绘制每个字段在target属性分组下的箱线图。也就是当target取分别取0或1时对应的x1到x8的取值分布情况

        通过箱线图,主要能够看出属性的分布情况,进而观察出该属性对target的影响是否较大,以及属性本身的分布是否均匀。针对分布不均或扎堆的属性,可以尝试将其调整为正态分布。

        x1到x8属性在标签分组下的箱线图如下:

         可以发现,x1,x2,x6属性分布不均匀x3属性的分布过于集中,导致大量的数据点成为离群点。x8属性的取值与target=0这一情况高度相关。

 1.2.3小时信息提取与绘图

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

sns.barplot(x='common_ts_hour', y='target', data=train_data)
plt.show()
# 统计每小时下的标签分布
hourly_label_counts = train_data.groupby('common_ts_hour')['target'].value_counts().unstack(fill_value=0)

# 绘制每小时下标签分布的变化
hourly_label_counts.plot(kind='bar', stacked=True)
plt.xlabel('Hour of Day')
plt.ylabel('Count')
plt.title('Label Distribution by Hour')
plt.legend(title='Label')
plt.show()

        这段代码用于从common_ts中提取小时,绘制每小时下标签分布的变化。前四行代码提取了小时属性,使用了时间戳的hour方法。然后使用了sns.barplot()函数来绘制柱状图。通过指定x='common_ts_hour'y='target',设置横轴为common_ts_hour字段,纵轴为target字段,表现了不同时间段下target的平均值。

 

hourly_label_counts = train_data.groupby('common_ts_hour')['target'].value_counts().unstack(fill_value=0)

         这一行代码用于绘制每小时下标签分布的变化。首先通过groupby函数将整个数据集以common_ts_hour属性,即小时属性进行分组,每个小时为一组。然后选取出target列,使用.value_counts()函数分别计算每组中不同target取值对应的数量

        然后,使用.unstack(fill_value=0)将结果重塑为以common_ts_hour为索引、target为列的数据框,并将缺失值填充为0。得到的hourly_label_counts数据框记录了每小时下各个标签的计数。每小时下标签分布的变化如下。

  1.2.4相关性分析热力图

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

        这段代码用于绘制相关性分析的热力图。

 1.2.5udmap属性分析

for i in range(1,10):
    key_mean_target = train_data.groupby('key' + str(i))['target'].mean()
    plt.bar(key_mean_target.index, key_mean_target)
    plt.show()

        这段代码用于统计每个key对应的标签均值。并绘制直方图。结果如下(仅列出key1的结果)

         其中,横轴是key1的取值,纵轴是该取值下对应target的平均值。

二、任务2.2

2.1任务内容

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

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

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

2.2代码解析

2.2.1交叉验证代码

        交叉验证的代码在学习文档中已经给出。

# 训练并验证SGDClassifier
pred = cross_val_predict(
    SGDClassifier(max_iter=10),
    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))

        这里训练并验证了四种模型,验证结果如下。

        其中,RandomForestClassifier模型的macro F1效果最好

        RandomForestClassifier 模型在处理分类问题时,由于其基于集成学习的特点,可以通过多个决策树的投票或平均来进行分类预测。这种方式对于计算宏平均F1得分非常有效。而此问题也是一个0-1分类问题。

具体原因如下:

  1. 集成学习的优势:RandomForestClassifier 模型是通过组合多个决策树模型来进行分类,每个决策树模型都对应着数据集的一个子集。多个模型的集成可以减小模型的方差和提高模型的鲁棒性,从而能够更好地处理多类别分类问题。

  2. 高召回率:RandomForestClassifier 模型通常具有较高的召回率,它能够捕捉到多个决策树模型中各自最优的特征和判定规则。在计算宏平均F1得分时,每个类别的预测结果都会考虑到,而 Random Forest 的集成模型通常能够全面而准确地覆盖多个类别。

2.2.2特征重要性可视化     

2.2.3再加入3个模型

        在上述四个模型的基础上,针对最优的RandomForestClassifier 模型,本文又尝试了多个不同的n_estimators属性进行训练,可以得出结果,当n_estimators=10或20时,f1得分最优

n_estimators=5

n_estimators=10

n_estimators=15

n_estimators=20

三、算法改进

        与上一次汇报相比,本算法进行了三处改进。

        其一是针对时间戳,增加了日期属性。除此之外,还挖掘了季度等其他与日期相关的属性,但效果不佳。因此与上一次打卡相比,只增加了日期属性

train_data['day'] = train_data['common_ts'].dt.day
test_data['day'] = test_data['common_ts'].dt.day  # 日属性

        其二是进行了异常值处理,删除了有空白的数据。也曾尝试过众数、平均数、中位数填充或直接填充0,但效果均不如直接删除缺失行效果好。

        其三是使用k-means算法进行了异常值处理,删去离群值,提升了测试集的f1得分。但提交系统后得分不佳,故暂时不使用异常检测。

def g(data):
    # Read the CSV file into a Pandas DataFrame
    # data = pd.read_csv(a)

    # Drop any rows with missing values
    data.dropna(inplace=True)
    # 计算每列的平均值
    # mean_values = data.mean()
    # mean_values = data.median()
    # mean_values = data.mode().iloc[0]
    # data.dropna(inplace=True)

    # 用平均值填充空白值
    # data.fillna(mean_values, inplace=True)

    # data.dropna(inplace=True)  # 删除空白
    # data.fillna(0)  # 填充0
    y = data
    y = y.drop(['udmap', 'common_ts', 'uuid'], axis=1)

    '''
    model = IsolationForest(contamination=0.05)
    model.fit(y)
    predictions = model.predict(y)
    data['anomaly'] = predictions

    # Print the anomalous samples
    anomalous_samples = data[y['anomaly'] == 1]
    return anomalous_samples.drop(['anomaly'], axis=1)

    # K均值聚类
    kmeans = KMeans(n_clusters=3)  # 3 25最优
    kmeans.fit(y)
    # 获取距离
    distances = kmeans.transform(y)

    # 计算距离阈值,剔除距离最远的5%的数据
    threshold = np.percentile(distances, 95)

    # 找出距离最远的5%的数据点的索引
    outliers_idx = np.where(distances > threshold)
    # 剔除距离最远的5%的数据
    filtered_data = data.drop(outliers_idx[0])'''
    return data

        目前系统得分0.76138

 四、总结

        与上一次汇报相比,进行了数据分析,分析了变量间的相互关系以及变量与预测值之间的关系,还进行了交叉验证,获得了目前为止最优的模型选择与参数选择。

        接下来的学习中,要分析添加异常检测后过拟合现象出现的原因并进行改进,还要在特征工程上进行进一步的学习。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值