任务2.1 数据分析与可视化
一. 准备知识
1.1 何为数据分析
探索性数据分析(Exploratory Data Analysis,简称EDA),是指对已有的数据(特别是调查或观察得来的原始数据)在尽量少的先验假定下进行探索,通过作图、制表、方程拟合、计算特征量等手段探索数据的结构和规律了解数据集,了解变量间的相互关系以及变量与预测值之间的关系的一种数据分析方法。可以进一步了解变量间的相互关系以及变量与预测值之间的存在关系。引导进行数据处理以及特征工程的步骤,使数据集的结构和特征集让预测更合理。目的在于熟悉、了解数据集,对数据集进行验证来确定所获得的数据集可以用于后续的机器学习或深度学习使用。
(图源学习手册)
![流程图](https://i-blog.csdnimg.cn/blog_migrate/aaae495ded57c61619af7d8b1a10c5c5.png)
1.2 实践步骤
实践步骤:
-
导入必要的库,特别是画图库。
-
计算特征与标签之间的相关性,展示热力图。
-
展示特征与标签分组统计图。
1.3 小尝试
导入学习手册中的实践代码,得到相关性热力图和x7的target值图像
二 . 回答任务2.1问题(附所用学习资源链接)
2.1字段类型
-
字段x1至x8为用户相关的属性,为匿名处理字段。添加代码对这些数据字段的取值分析,那些字段为数值类型?那些字段为类别类型?
-
代码:
//前面代码和基础baseline一致,不再赘述:导入库(与基础baseline相比增加了画图库) 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') //使用.dtypes方法获取这些字段的数据类型 train_data[['x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7', 'x8']].dtypes (还可以用.shape和 .info查看其它基本信息,以便更好地分析数据)
输出结果:x1—x8均为数值型
相关资料:Python 数据处理(十二)—— dtypes - 知乎 (zhihu.com)
pandas中查看数据类型的几种方式 - 简书 (jianshu.com)
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()
输出结果:
由于本人不会分析,搜了下怎么看箱型图
看完还不是很懂,但是根据图像可以初步分析出:
x3有很多异常值(离群点)。
x8的target=0几乎只有顶部的线,说明高度相关。
x1,x2,x6有线的重合,大概是分布不均?
相关资料:
Python数据可视化(七):箱线图绘制 - 简书 (jianshu.com)(讲了绘制单个和多个箱线图的代码)
如何深刻理解箱线图(boxplot) - 知乎 (zhihu.com)
箱线图怎样分析? - 知乎 (zhihu.com)(怎么根据箱线图分析数据)
2.3每小时下标签分布的变化
-
从common_ts中提取小时,绘制每小时下标签分布的变化。
//照例改时间戳,使用 pd.to_datetime() 函数将时间戳列转换为 datetime 类型 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') //把ms的数据用dt.hour这种属性设置提成小时 train_data['common_ts_hour'] = train_data['common_ts'].dt.hour test_data['common_ts_hour'] = test_data['common_ts'].dt.hour
(使用dt.hour前后对比)
-
Python可视化 | Seaborn5分钟入门(二)——barplot和countplot - 知乎 (zhihu.com)(讲解barplot和countplot异同)
-
画每小时标签分布的变化(copy其他大佬的):首先通过groupby函数将整个数据集以common_ts_hour属性,即小时属性进行分组,每个小时为一组。然后选取出target列,使用.value_counts()函数分别计算每组中不同target取值对应的数量。 然后,使用
.unstack(fill_value=0)
将结果重塑为以common_ts_hour
为索引、target
为列的数据框,并将缺失值填充为0。得到的hourly_target_value
数据框记录了每小时下各个标签的计数。每小时下标签分布的变化如下。 -
//首先通过groupby函数将整个数据集以common_ts_hour属性,即小时属性进行分组,每个小时为一组。然后选取出target列,使用.value_counts()函数分别计算每组中不同target取值对应的数量。 hourly_target_value = train_data.groupby('common_ts_hour')['target'].value_counts().unstack(fill_value=0) hourly_target_value.plot(kind='bar', stacked=True) plt.xlabel('Hour of Day') plt.ylabel('count') plt.title('target Distribution by Hour') plt.legend(title='target')
本弱智直接设置x=’common_ts_hour"和hue='target'绘制的countbar(好像target属性对比没有上面的直观)
2.4统计每个key对应的标签均值,绘制直方图
-
对udmap进行onehot,统计每个key对应的标签均值,绘制直方图。
-
用i循环连续绘制key1-key9对应直方图。首先通过groupby函数将整个数据集以key属性进行分组,每个key为一组。然后选取出target列求均值
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()
输出:电脑卡死了()
![](https://i-blog.csdnimg.cn/blog_migrate/8a734d315ec389e52bace6f3ee71737d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2a1edc3c451f1d2b6cc296982c1d15be.png)
任务2.2模型交叉验证
一 . 准备知识
1.1 何为交叉验证
交叉验证(Cross-Validation)是机器学习中常用的一种模型评估方法,用于评估模型的性能和泛化能力。它的主要目的是在有限的数据集上,尽可能充分地利用数据来评估模型,避免过拟合或欠拟合,并提供对模型性能的更稳健的估计。
交叉验证的基本思想是将原始的训练数据划分为多个子集(也称为折叠),然后将模型训练和验证进行多次循环。在每一次循环中,使用其中一个子集作为验证集,其他子集作为训练集。这样可以多次计算模型的性能指标,并取这些指标的平均值作为最终的模型性能评估结果。
1.2 常见方法
【机器学习】Cross-Validation(交叉验证)详解 - 知乎 (zhihu.com)
1.The Validation Set Approach
把整个数据集分成两部分,一部分用于训练,一部分用于验证,这也就是训练集(training set)和测试集(test set)。
2.Cross-Validation
2.1 LOOCV
LOOCV方法,即(Leave-one-out cross-validation)。像Test set approach一样,LOOCV方法也包含将数据集分为训练集和测试集这一步骤。但是不同的是,我们现在只用一个数据作为测试集,其他的数据都作为训练集,并将此步骤重复N次(N为数据集的数据数量)。假设我们现在有n个数据组成的数据集,那么LOOCV的方法就是每次取出一个数据作为测试集的唯一元素,而其他n-1个数据都作为训练集用于训练模型和调参。结果就是我们最终训练了n个模型,每次都能得到一个MSE。而计算最终test MSE则就是将这n个MSE取平均值
为了解决计算成本太大的弊端,又有人提供了下面的式子,使得LOOCV计算成本和只训练一个模型一样快。
2.2 K-fold Cross Validation
另外一种折中的办法叫做K折交叉验证,和LOOCV的不同在于,我们每次的测试集将不再只包含一个数据,而是多个,具体数目将根据K的选取决定。一般来说,根据经验我们一般选择k=5或10。
不难理解,其实LOOCV是一种特殊的K-fold Cross Validation(K=N)。
上面我们讲的都是回归问题,所以用MSE来衡量test error。如果是分类问题,那么我们可以用以下式子来衡量Cross-Validation的test error:
其中Erri表示的是第i个模型在第i组测试集上的分类错误的个数。
1.3 实操尝试
实操步骤:
-
加载数据集,并对数据进行编码
-
导入多个模型进行交叉验证
-
比较模型的F1精度
导入学习手册中的代码
# 导入模型
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=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))
结果:
![]() DecisionTreeClassifier |
![]() |
![]() MultinomialNB |
![]() |
二. 回答任务2.2问题
2.1在上面模型中哪一个模型的macro F1效果最好,为什么这个模型效果最好?
显然RandomForestClassifier 模型的f1-score最高。
原因:
随机森林(Random Forest)是属于集成学习的一种组合分类算法(确切说是属于bagging),集成学习的核心思想就是将若干个弱(基)分类器组合起来,得到一个分类性能显著优越的强分类器。如果各弱分类器之前没有强依赖关系、可并行生成,就可以使用随机森林算法。 优势如下:
- 模型训练结果准确度高
- 随机性的引入,使得随机森林不容易过拟合,有很好的抗噪声能力,对异常点离群点不敏感
- 能处理很高维度的数据,并且不用做特征选择,最终训练结果,可以对特种额排序,选择比较重要的特征
- 既能处理离散型数据,也能处理连续型数据,数据集无需规范化(归一化)。
- 模型的泛化能力较强。实现简单,训练速度快,可以得到变量重要性排序(计算每个特征在分裂时被选到的次数或者某个特征不纯度平均下降了多少)
- 容易实现并行化
- 在创建随机森林的时候,对generlization error使用的是无偏估计,不需要额外的验证集
2.2 使用树模型训练,然后对特征重要性进行可视化;
参考了【机器学习】随机森林预测并可视化特征重要性_python随机森林特征重要性_白̵敬̵̵亭的博客-CSDN博客
代码:
# 导入模型
from sklearn.ensemble import RandomForestClassifier
# 导入交叉验证和评价指标
from sklearn.model_selection import cross_val_predict
from sklearn.metrics import classification_report
//训练模型
RF = RandomForestRegressor(n_estimators=5)
Y=train_data['target']
X=train_data.drop(['udmap', 'common_ts', 'uuid', 'target'], axis=1)
RF.fit(X,Y)
feature_importances = RF.feature_importances_
# 创建特征名列表
feature_names = list(X.columns)
# 创建一个DataFrame,包含特征名和其重要性得分
feature_importances_df = pd.DataFrame({'feature': feature_names, 'importance': feature_importances})
# 对特征重要性得分进行排序
feature_importances_df = feature_importances_df.sort_values('importance', ascending=False)
# 颜色映射
colors = plt.cm.viridis(np.linspace(0, 1, len(feature_names)))
# 可视化特征重要性
fig, ax = plt.subplots(figsize=(10, 6))
ax.barh(feature_importances_df['feature'], feature_importances_df['importance'], color=colors)
ax.invert_yaxis() # 翻转y轴,使得最大的特征在最上面
ax.set_xlabel('feature importance', fontsize=12) # 图形的x标签
ax.set_title('visualize',fontsize=16)
for i, v in enumerate(feature_importances_df['importance']):
ax.text(v + 0.01, i, str(round(v, 3)), va='center', fontname='Times New Roman', fontsize=10)
# # 设置图形样式
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.show()
2.3 再加入3个模型训练,对比模型精度
可以调原来模型的数值啥的,以下为随机森林模型n_estimators=10,15,20的结果
综合看,n_estimators=15和20时,模型精度较高。
任务2.3 特征工程
一.准备知识
1.1特征工程
特征工程(Feature Engineering)特征工程是将原始数据转化成更好的表达问题本质的特征的过程,使得将这些特征运用到预测模型中能提高对不可见数据的模型预测精度。
- 数据中的特征对预测的模型和获得的结果有着直接的影响。可以这样认为,特征选择和准备越好,获得的结果也就越好。这是正确的,但也存在误导。预测的结果其实取决于许多相关的属性:比如说能获得的数据、准备好的特征以及模型的选择。
-
方法与步骤
1.2 实践步骤与尝试
-
common_ts_day
特征:从时间戳common_ts
中提取出日期部分的天数,以创建一个新的特征表示访问日期。 -
x1_freq
和x1_mean
特征:计算特征x1
在训练集中的频次(出现次数)以及在训练集中对应的目标列target
的均值。这些特征可以捕捉x1
特征的重要性和与目标的关系。 -
类似地,对于其他
x2
、x3
、x4
、x6
、x7
和x8
特征,进行了类似的操作,分别计算它们在训练集中的频次和均值。
老规矩:copy学习手册实践代码
二。回答2.3问题
2.1加入特征之后模型的精度有什么变化?
以RandomForestClassifier模型为例,可以发现精度上升了
![]() |
![]() |
2.2 思考并加入3个额外的特征,并观测模型精度的变化
加入特征'x3_mean''x5_freq'"x5_mean'
train_data['x3_mean'] = train_data['x3'].map(train_data.groupby('x3')['target'].mean())
test_data['x3_mean'] = test_data['x3'].map(train_data.groupby('x3')['target'].mean())
train_data['x5_freq'] = train_data['x5'].map(train_data['x5'].value_counts())
test_data['x5_freq'] = test_data['x5'].map(train_data['x5'].value_counts())
train_data['x5_mean'] = train_data['x5'].map(train_data.groupby('x5')['target'].mean())
test_data['x5_mean'] = test_data['x5'].map(train_data.groupby('x5')['target'].mean())
结果可发现精度依旧提高
今日分数:0.62635
(试了下随机数模型还降分了……/(ㄒoㄒ)/~~