字段x1至x8为用户相关的属性,为匿名处理字段。添加代码对这些数据字段的取值分析,那些字段为数值类型?那些字段为类别类型?
对于数值类型的字段,考虑绘制在标签分组下的箱线图。
从common_ts中提取小时,绘制每小时下标签分布的变化。
对udmap进行onehot,统计每个key对应的标签均值,绘制直方图。
# 导入库
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字段的属性如下所示,可以发现他们都是数值型的。
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这一情况高度相关。
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
数据框记录了每小时下各个标签的计数。每小时下标签分布的变化如下。
# 相关性热力图
sns.heatmap(train_data.corr().abs(), cmap='YlOrRd')
plt.show()
这段代码用于绘制相关性分析的热力图。
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的平均值。
在上面模型中哪一个模型的macro F1效果最好,为什么这个模型效果最好?
使用树模型训练,然后对特征重要性进行可视化;
再加入3个模型训练,对比模型精度;
交叉验证的代码在学习文档中已经给出。
# 训练并验证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分类问题。
具体原因如下:
集成学习的优势:RandomForestClassifier 模型是通过组合多个决策树模型来进行分类,每个决策树模型都对应着数据集的一个子集。多个模型的集成可以减小模型的方差和提高模型的鲁棒性,从而能够更好地处理多类别分类问题。
高召回率:RandomForestClassifier 模型通常具有较高的召回率,它能够捕捉到多个决策树模型中各自最优的特征和判定规则。在计算宏平均F1得分时,每个类别的预测结果都会考虑到,而 Random Forest 的集成模型通常能够全面而准确地覆盖多个类别。
在上述四个模型的基础上,针对最优的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
与上一次汇报相比,进行了数据分析,分析了变量间的相互关系以及变量与预测值之间的关系,还进行了交叉验证,获得了目前为止最优的模型选择与参数选择。
接下来的学习中,要分析添加异常检测后过拟合现象出现的原因并进行改进,还要在特征工程上进行进一步的学习。