数据挖掘小案例

    技术2022-07-11  80

    数据挖掘步骤

    一 、数据取样:

    对数据进行精选,以保证数据的科学性、有效性、均衡性等。 二、数据探索与预处理:

    对数据的特征进行探索,对数据进行清洗(去除错误数据、去除噪声、填补缺失值等过程),特征提取,降维等操作,数量、异常值、缺失值等。对数据进行标准化。 三、模式发现:

    发现问题是属于哪一类,选取合适的数据挖掘方法。 四、构建模型:

    将经过预处理之后的可用数据代入模型进行数据挖掘。 五、模型评价:

    对构建的模型进行评价(不同类别的模型评价方法可能不同),若效果不理想,则进一步调整模型。

    为什么选择这个案例?

    1.辅助媒体产出奥运会相关文案

    数据记录了120年的奥运会参赛国家、人员以及成绩等相关信息,案例主要从运动员身高与体重的角度进行分析, 总览奥运会发展的历史过程。分析结果可帮助媒体行业向用户更直观展示奥运会的发展过程,拉动用户兴趣,增加活跃度。 2.把实际问题转化为数学模型,达到学以致用的目的。

    一 、数据取样

    数据集包括从1896年雅典奥运会到2016年里约奥运会的所有比赛,数据源下载地址:https://www.juhe.cn/market/product?id=10246 下载完成有两个文件:athlete_events.csv以及noc_regions.csv,下面是数据概览,如果直接想要数据集的可以在下方留言。 (1) athlete_events.csv文件: 记录着运动员赛事(运动员的名字,参加的比赛,体重等等) 文件说明: 该文件包含271116行和15列;每行对应一个运动员参加单个奥林匹克项目(运动员项目)的情况。 ID--------每个运动员的唯一编号; Name------运动员的名字; Sex-------M or F; Age-------岁数(整数); Height----身高(厘米); Weight----重量(千克); Team------所属团队名称; NOC-------国家奥委会三字母代码3-letter code; Games-----哪一年哪个季节的项目; Year------年份(整数); Season----夏季或冬季; City------主办城市; Sport-----体育活动; Event-----事件(项目名); Meda1-----金,银,铜或NA;

    (2)noc_regions.csv 文件:记录着国家奥委会地区信息(National Olympic Committee,缩写为NOC)

    导入相关的库

    import numpy as np import pandas as pd import seaborn as sns from matplotlib import pyplot as plt import os

    读取文件,获取数据集

    dirpath = 'E:\Jupyter\A\B' data = pd.read_csv(os.path.join(dirpath, 'athlete_events.csv')) regions = pd.read_csv(os.path.join(dirpath, 'noc_regions.csv')) #通过已知信息,我们发现文件1和文件2的NOC字段相同,采用左连接将两个文件连接起来 merged = pd.merge(data, regions, on='NOC', how='left')

    打印前五行数据

    # 过滤出金牌数据 goldMedals = merged[(merged.Medal == 'Gold')] #打印出前五行数据 goldMedals.head()

    二、数据探索与预处理

    检查年龄是否有NaN

    goldMedals.isnull().any()

    #显示数据的基本信息

    goldMedals.info()

    #过滤出非空的值

    notNullMedals = goldMedals[(goldMedals['Height'].notnull()) & (goldMedals['Weight'].notnull())] #再查看一下非空数据的信息 notNullMedals.head()

    #pandas的describe可以用来展示数据的一些描述性统计信息

    notNullMedals.describe()

    三、模式发现

    选择线性回归算法, 人的身高和体重是两种相关性的量,可以用回归分析来分析。

    通过seaborn可视化快速简便地探索数据集

    plt.subplots(figsize=(10, 6)) plt.xlabel('Height', fontsize=12) plt.ylabel('Weight', fontsize=12) plt.title('Height and Weight') # 绘制数据并拟合出数据的线性回归模型 sns.regplot(x='Height', y='Weight', data=notNullMedals,ci=None) #默认参数ci=95,置信度(指的是发生事件A的基础上发生事件B的概率,即条件概率)为0.95的置信区间,此处数据过多,设为None线性回归拟合。

    特殊值数据 箱型图

    plt.figure(figsize=(20,10)) plt.tight_layout() # 紧凑型布局,图更干净好看 sns.boxplot('Height', 'Weight', data=notNullMedals) plt.rcParams['font.sans-serif'] = ['SimHei']#添加中文字体支持 plt.rcParams['axes.unicode_minus'] = False #添加中文字体支持 plt.xticks(rotation=90) plt.title('金牌运动员身高体重关系')

    我们发现,基本在回归线上,但是有一些是比较异常的,下面查看体重大于120公斤的参加的是什么项目

    notNullMedals.loc[notNullMedals['Weight'] > 120]

    查询可知,主要包括了以下三种运动项目,举重项目对体重的要求确实要高,不同级别的体重只能参加不同级别的赛事 Athletics 竞技;田径运动 Weightlifting 举重 Judo 柔道

    男女分类,比较男性和女性的身高体重关系还是有区别的。

    Men_Medals = notNullMedals[(notNullMedals.Sex == 'M')] Women_Medals = notNullMedals[(notNullMedals.Sex == 'F')] Men_Medals.info()#男金牌运动员信息 Women_Medals.info()#女金牌运动员信息

    四、构建模型

    采用线性模型,为什么不采用逻辑回归? 线性回归要求因变量必须是连续性数据变量;逻辑回归要求因变量必须是分类变量,二分类或者多分类的;比如要分析性别、年龄、身高、饮食习惯对于体重的影响,如果这个体重是属于实际的重量,是连续性的数据变量,这个时候就用线性回归来做;如果将体重分类,分成了高、中、低这三种体重类型作为因变量,则采用logistic回归。

    下面按照男运动员和女运动员来分析 分训练集和测试集,train_x,train_y为训练集,test_x和test_y 为测试集

    男运动员

    #utils模块的shuffle方法打乱数集 import sklearn.utils as su x = Men_Medals['Height'] y = Men_Medals['Weight'] #打乱原始数据集的输入和输出 #random_state随机种子,下次random_state=7生成的打乱顺序一样 x,y = su.shuffle(x,y,random_state=7) train_size = int (len(x)*0.8)#8/2 train_x,test_x,train_y,test_y = x[:train_size],x[train_size:],y[:train_size],y[train_size:] print(train_x.shape, train_y.shape)#查看数组的维数 print(test_x.shape, test_y.shape)#查看数组的维数 #划分测试集和训练集 train_x = train_x.values.reshape(-1, 1) train_y = train_y.values.reshape(-1, 1) test_x = test_x.values.reshape(-1, 1) test_y = test_y.values.reshape(-1, 1) #导入线性回归模块 import sklearn.linear_model as lm # 创建模型----线性回归 model = lm.LinearRegression() # 训练模型 model.fit(train_x, train_y) # 根据输入预测输出 pred_y = model.predict(test_x) #评估训练结果误差(metrics) import sklearn.metrics as sm # 平均绝对值误差:1/m∑|实际输出-预测输出| print('平均绝对值误差:',sm.mean_absolute_error(test_y, pred_y)) # 中位绝对值误差:MEDIAN(|实际输出-预测输出|) print('中位绝对值误差:',sm.median_absolute_error(test_y, pred_y)) # R2得分,(0,1]区间的分值。分数越高,误差越小。 print('R2得分: ',sm.r2_score(test_y, pred_y))

    可视化

    #可视化 plt.figure('Linear Regression', facecolor='lightgray') plt.title('Linear Regression', fontsize=20) plt.xlabel('Height', fontsize=14) plt.ylabel('Weight', fontsize=14) plt.tick_params(labelsize=10) plt.grid(linestyle=':') plt.scatter(train_x, train_y, marker='s', c='dodgerblue', alpha=0.5, s=80, label='Training')#训练集,正方形 plt.scatter(test_x, test_y, marker='D', c='orangered', alpha=0.5, s=60, label='Testing')#测试集,钻石 plt.scatter(test_x, pred_y, c='orangered',alpha=0.5, s=80, label='Predicted')#预测,s参数代表的是形状的大小 plt.plot(test_x, pred_y, '--', c='limegreen', label='Regression', linewidth=1) plt.legend() plt.show()

    #可视化----测试值和真实值 plt.scatter(test_y, pred_y) plt.xlabel('True') plt.ylabel('Predictions')

    女金牌运动员过程同上,此处不再赘述,下面再统一放上代码

    因为是在jupyter notebook进行的编程,所以导出的py文件有相应的行号。

    # ### 导入相关的库 # In[1]: import numpy as np import pandas as pd import seaborn as sns from matplotlib import pyplot as plt import os # ### 读取文件,获取数据集 # In[2]: dirpath = 'E:\Jupyter\A\B' data = pd.read_csv(os.path.join(dirpath, 'athlete_events.csv')) regions = pd.read_csv(os.path.join(dirpath, 'noc_regions.csv')) # In[3]: #通过已知信息,我们发现文件1和文件2的NOC字段相同,采用左连接将两个文件连接起来 merged = pd.merge(data, regions, on='NOC', how='left') # In[4]: # 过滤出金牌数据 goldMedals = merged[(merged.Medal == 'Gold')] #打印出前五行数据 goldMedals.head() # 下面进行预处理操作 # # ## 二、数据探索与预处理 # In[5]: # 检查年龄是否有NaN goldMedals.isnull().any() # In[6]: #显示数据的基本信息 goldMedals.info() # In[7]: #过滤出非空的值 notNullMedals = goldMedals[(goldMedals['Height'].notnull()) & (goldMedals['Weight'].notnull())] # In[8]: #再查看一下非空数据的信息 notNullMedals.head() # In[9]: #pandas的describe可以用来展示数据的一些描述性统计信息 notNullMedals.describe() # # 三、模式发现 # # 选择线性回归算法, 人的身高和体重是两种相关性的量,可以用回归分析来分析 # ### 通过seaborn可视化快速简便地探索数据集 # In[10]: plt.subplots(figsize=(10, 6)) plt.xlabel('Height', fontsize=12) plt.ylabel('Weight', fontsize=12) plt.title('Height and Weight') # 绘制数据并拟合出数据的线性回归模型 sns.regplot(x='Height', y='Weight', data=notNullMedals,ci=None) #默认参数ci=95,置信度(指的是发生事件A的基础上发生事件B的概率,即条件概率)为0.95的置信区间,此处数据过多,设为None线性回归拟合。 # ### 特殊值数据 # 我们发现,基本在回归线上,但是有一些是比较异常的,下面查看体重大于120公斤的参加的是什么项目 # In[11]: plt.figure(figsize=(20,10)) plt.tight_layout() # 紧凑型布局,图更干净好看 sns.boxplot('Height', 'Weight', data=notNullMedals) plt.rcParams['font.sans-serif'] = ['SimHei']#添加中文字体支持 plt.rcParams['axes.unicode_minus'] = False #添加中文字体支持 plt.xticks(rotation=90) plt.title('金牌运动员身高体重关系') # In[12]: notNullMedals.loc[notNullMedals['Weight'] > 120] # 查询可知,主要包括了以下三种运动项目,举重项目对体重的要求确实要高,不同级别的体重只能参加不同级别的赛事 # Athletics 竞技;田径运动 # Weightlifting 举重 # Judo 柔道 # ### 男女分类 # # In[13]: Men_Medals = notNullMedals[(notNullMedals.Sex == 'M')] Women_Medals = notNullMedals[(notNullMedals.Sex == 'F')] # In[14]: Men_Medals.info()#男金牌运动员信息 # In[15]: Women_Medals.info()#女金牌运动员信息 # # # 四、构建模型 # # ## 线性模型 # 为什么不采用逻辑回归? # 线性回归要求因变量必须是连续性数据变量;逻辑回归要求因变量必须是分类变量,二分类或者多分类的;比如要分析性别、年龄、身高、饮食习惯对于体重的影响,如果这个体重是属于实际的重量,是连续性的数据变量,这个时候就用线性回归来做;如果将体重分类,分成了高、中、低这三种体重类型作为因变量,则采用logistic回归。 # # 五、模型评估 # #### 按比例划分样本集 # 在K-Folds交叉验证中,我们将数据分割成k个不同的子集。我们使用第k-1个子集来训练数据,并留下最后一个子集作为测试数据。接下来结束模型之后,我们对测试集进行测试。 # # # #### 下面按照男运动员和女运动员来分析 # # 分训练集和测试集 # train_x,train_y为训练集,test_x和test_y 为测试集 # # #### 1 男运动员 # In[16]: #utils模块的shuffle方法打乱数集 import sklearn.utils as su x = Men_Medals['Height'] y = Men_Medals['Weight'] #打乱原始数据集的输入和输出 #random_state随机种子,下次random_state=7生成的打乱顺序一样 x,y = su.shuffle(x,y,random_state=7) train_size = int (len(x)*0.8)#8/2 train_x,test_x,train_y,test_y = x[:train_size],x[train_size:],y[:train_size],y[train_size:] print(train_x.shape, train_y.shape)#查看数组的维数 print(test_x.shape, test_y.shape)#查看数组的维数 # In[17]: #划分测试集和训练集 train_x = train_x.values.reshape(-1, 1) train_y = train_y.values.reshape(-1, 1) test_x = test_x.values.reshape(-1, 1) test_y = test_y.values.reshape(-1, 1) # In[18]: #导入线性回归模块 import sklearn.linear_model as lm # 创建模型----线性回归 model = lm.LinearRegression() # 训练模型 model.fit(train_x, train_y) # 根据输入预测输出 pred_y = model.predict(test_x) # #模型评估,准确度 # print('男金牌运动员Score:',model.score(test_x,test_y)) # In[19]: #评估训练结果误差(metrics) import sklearn.metrics as sm # 平均绝对值误差:1/m∑|实际输出-预测输出| print('平均绝对值误差:',sm.mean_absolute_error(test_y, pred_y)) # 中位绝对值误差:MEDIAN(|实际输出-预测输出|) print('中位绝对值误差:',sm.median_absolute_error(test_y, pred_y)) # R2得分,(0,1]区间的分值。分数越高,误差越小。 print('R2得分: ',sm.r2_score(test_y, pred_y)) # In[20]: #可视化 plt.figure('Linear Regression', facecolor='lightgray') plt.title('Linear Regression', fontsize=20) plt.xlabel('Height', fontsize=14) plt.ylabel('Weight', fontsize=14) plt.tick_params(labelsize=10) plt.grid(linestyle=':') plt.scatter(train_x, train_y, marker='s', c='dodgerblue', alpha=0.5, s=80, label='Training')#训练集 plt.scatter(test_x, test_y, marker='D', c='orangered', alpha=0.5, s=60, label='Testing')#测试集 plt.scatter(test_x, pred_y, c='orangered',alpha=0.5, s=80, label='Predicted')#预测 plt.plot(test_x, pred_y, '--', c='limegreen', label='Regression', linewidth=1) plt.legend() plt.show() # In[21]: #可视化----测试值和真实值 plt.scatter(test_y, pred_y) plt.xlabel('True') plt.ylabel('Predictions') # #### 2 女金牌运动员 # 过程同上 # In[22]: #utils模块的shuffle方法打乱数集 import sklearn.utils as su x = Women_Medals['Height'] y = Women_Medals['Weight'] #打乱原始数据集的输入和输出 #random_state随机种子,下次random_state=7生成的打乱顺序一样 x,y = su.shuffle(x,y,random_state=7) train_size = int (len(x)*0.8)#8/2 train_x,test_x,train_y,test_y = x[:train_size],x[train_size:],y[:train_size],y[train_size:] print(train_x.shape, train_y.shape)#查看数组的维数 print(test_x.shape, test_y.shape)#查看数组的维数 # In[23]: #划分测试集和训练集 train_x = train_x.values.reshape(-1, 1) train_y = train_y.values.reshape(-1, 1) test_x = test_x.values.reshape(-1, 1) test_y = test_y.values.reshape(-1, 1) # In[24]: #导入线性回归模块 import sklearn.linear_model as lm # 创建模型----线性回归 model = lm.LinearRegression() # 训练模型 model.fit(train_x, train_y) # 根据输入预测输出 pred_y = model.predict(test_x) # In[25]: import sklearn.metrics as sm#评估训练结果误差(metrics) # 平均绝对值误差:1/m∑|实际输出-预测输出| print('平均绝对值误差:',sm.mean_absolute_error(test_y, pred_y)) # 中位绝对值误差:MEDIAN(|实际输出-预测输出|) print('中位绝对值误差:',sm.median_absolute_error(test_y, pred_y)) # R2得分,(0,1]区间的分值。分数越高,误差越小。 print('R2得分: ',sm.r2_score(test_y, pred_y)) # In[26]: #可视化 plt.figure('Linear Regression', facecolor='lightgray') plt.title('Linear Regression', fontsize=20) plt.xlabel('Height', fontsize=14) plt.ylabel('Weight', fontsize=14) plt.tick_params(labelsize=10) plt.grid(linestyle=':') plt.scatter(train_x, train_y, marker='s', c='dodgerblue', alpha=0.5, s=80, label='Training')#训练集 plt.scatter(test_x, test_y, marker='D', c='orangered', alpha=0.5, s=60, label='Testing')#测试集 plt.scatter(test_x, pred_y, c='orangered',alpha=0.5, s=80, label='Predicted')#预测 plt.plot(test_x, pred_y, '--', c='limegreen', label='Regression', linewidth=1) plt.legend() plt.show() # In[27]: #可视化----测试值和真实值 plt.scatter(test_y, pred_y) plt.xlabel('True') plt.ylabel('Predictions') # ### sklearn.model_selection 的train_test_split方便操作 # 更改训练集和测试集的比例 # # In[28]: # Necessary imports: from sklearn.model_selection import train_test_split #分割测试集 # from sklearn.model_selection import cross_val_predict#预测 # from sklearn.model_selection import cross_val_score#准确度 # In[29]: #utils模块的shuffle方法打乱数集 import sklearn.utils as su x1 = Men_Medals['Height'][:6730].values.reshape(-1, 1)# 本来有6731个数据,删去最后一个数据,使得能够7:3比例分割 y1 = Men_Medals['Weight'][:6730].values.reshape(-1, 1) x2 = Women_Medals['Height'][:6730].values.reshape(-1, 1) y2 = Women_Medals['Weight'][:6730].values.reshape(-1, 1) #打乱原始数据集的输入和输出 #random_state随机种子,下次random_state=7生成的打乱顺序一样 x1,y1 = su.shuffle(x1,y1,random_state=7) x2,y2 = su.shuffle(x2,y2,random_state=7) # In[30]: #导入线性回归模块 import sklearn.linear_model as lm # 9:1比例划分测试集和训练集 train_x, test_x, train_y, test_y = train_test_split(x1, y1, test_size=0.1) print(train_x.shape, train_y.shape)#查看数组的维数 print(test_x.shape, test_y.shape) # 创建模型----线性回归 model = lm.LinearRegression() # 训练模型 model.fit(train_x, train_y) # 根据输入预测输出 pred_y = model.predict(test_x) # In[31]: #评估训练结果误差(metrics) import sklearn.metrics as sm # 平均绝对值误差:1/m∑|实际输出-预测输出| print('平均绝对值误差:',sm.mean_absolute_error(test_y, pred_y)) # 中位绝对值误差:MEDIAN(|实际输出-预测输出|) print('中位绝对值误差:',sm.median_absolute_error(test_y, pred_y)) # R2得分,(0,1]区间的分值。分数越高,误差越小。 print('R2得分: ',sm.r2_score(test_y, pred_y)) # In[32]: #可视化----测试值和真实值 plt.scatter(test_y, pred_y) plt.xlabel('True') plt.ylabel('Predictions') # 女金牌运动员 # In[33]: #导入线性回归模块 import sklearn.linear_model as lm # 9:1比例划分测试集和训练集 train_x, test_x, train_y, test_y = train_test_split(x2, y2, test_size=0.1) print(train_x.shape, train_y.shape)#查看数组的维数 print(test_x.shape, test_y.shape) # 创建模型----线性回归 model = lm.LinearRegression() # 训练模型 model.fit(train_x, train_y) # 根据输入预测输出 pred_y = model.predict(test_x) # In[34]: #评估训练结果误差(metrics) import sklearn.metrics as sm # 平均绝对值误差:1/m∑|实际输出-预测输出| print('平均绝对值误差:',sm.mean_absolute_error(test_y, pred_y)) # 中位绝对值误差:MEDIAN(|实际输出-预测输出|) print('中位绝对值误差:',sm.median_absolute_error(test_y, pred_y)) # R2得分,(0,1]区间的分值。分数越高,误差越小。 print('R2得分: ',sm.r2_score(test_y, pred_y)) # In[35]: #可视化----测试值和真实值 plt.scatter(test_y, pred_y) plt.xlabel('True') plt.ylabel('Predictions')

    总结

    我们发现,经过调整训练集和测试集的比例,可以提高预测的概率。 8:2比例划分的时候,男女运动员预测准确率分别为:

    平均绝对值误差 : 6.468241160875661 中位绝对值误差 : 4.987672129090541 男金牌运动员R2得分 : 0.5415336138589381

    平均绝对值误差 : 5.263819850060556 中位绝对值误差 : 3.919112100002536 女金牌运动员R2得分: 0.5042538766701146 采用9:1划分比例划分,男女运动员预测准确率变为:

    平均绝对值误差 : 6.409984653111301 中位绝对值误差 : 5.05029332334918 男金牌运动员R2得分 : 0.6118971581875867

    平均绝对值误差 : 5.035672223424354 中位绝对值误差 : 3.5369478461228 女金牌运动员R2得分 : 0.5416717045293267

    附: 但是,可以优化的地方还有很多,比如把体重超标的异常值和太轻的没有去掉,比赛类型的不同影响情况也不一样,还可以对数据进行标准化等,数据集还有其他的属性没有用到,大家也可以自行进行挖掘,本文仅仅是对数据挖掘的进行入门的基本学习,难免有很多不足的地方,还请各位见谅,今天是7月1号,也是香港回归23周年,2020太不平凡,大事小事,大家都辛苦了,祝祖国国泰民安。

    Processed: 0.012, SQL: 9