探究120年裏奧運會金牌運動員身高與體重的數學模型

數據挖掘步驟

一 、數據取樣:

對數據進行精選,以保證數據的科學性、有效性、均衡性等。
二、數據探索與預處理:

對數據的特徵進行探索,對數據進行清洗(去除錯誤數據、去除噪聲、填補缺失值等過程),特徵提取,降維等操作,數量、異常值、缺失值等。對數據進行標準化。
三、模式發現:

發現問題是屬於哪一類,選取合適的數據挖掘方法。
四、構建模型:

將經過預處理之後的可用數據代入模型進行數據挖掘。
五、模型評價:

對構建的模型進行評價(不同類別的模型評價方法可能不同),若效果不理想,則進一步調整模型。

爲什麼選擇這個案例?

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太不平凡,大事小事,大家都辛苦了,祝祖國國泰民安。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章