點擊可下載完整電子書《阿里雲機器學習PAI-DSW入門指南》
大數據算命系列之用機器學習評估你的相親戰鬥力
試愛情,80%準確率! 俗話說,名如其人,緣分就是人生的後半生,為了尋找真緣分的大有人在,因此也就有了姓名緣分測試。 您現在是不是也正在心動猶豫,也想要一個屬於自己的名字配對緣分測試了呢?那就請您趕緊行動吧!" 以上這段話,你一定已經在很多個微信公眾號的尾部,電視節目之間的廣告以及奇奇怪怪的小網站上看到過了吧。
你一定很好奇,這個緣分測試背後到底是不是有科學依據支撐的。
今天,作為數據科學老司機的我,雖然不能直接幫你測試你和某個特定的人直接的緣分,但是我們可以藉助哥倫比亞大學多年研究相親找對象的心血,通過幾個簡單的特徵來評估你的相親戰鬥力指數。
具體模型的測試頁面在這裡在正式開始實驗之前,我們需要尋找一個簡單好用方便上手的工具,這裡我推薦一波阿里雲的DSW探索者版,它對於個人開發者是免費的,同時還有免費的GPU資源可以使用,同時實驗的數據還會免費保存30天。點擊這裡就可以使用,不需要購買,只要登陸就可以使用。今天我們就會通過這個工具來探索人性的奧祕,走進兩性關係的神祕空間嘿嘿嘿。
整個實驗的數據收集於一個從2002年到2004年的線下快速相親的實驗。在這個實驗中,參與者被要求參加多輪與異性進行的快速相親,每輪相親持續4分鐘,在4分鐘結束後,參與者雙方會被詢問是否願意與他們的對象再見面。只有當雙方都回答了“是”的時候,這次相親才算是配對成功。
同時,參與者也會被要求通過以量化的方式從 外觀吸引力,真誠度,智商,風趣程度,事業心,興趣愛好 這六個方向來評估他們的相親對象。
這個數據集同時也包含了很多參加快速相親的參與者的其他相關信息,比如地理位置,喜好,對於理想對象的偏好,收入水平,職業以及教育背景等等。關於整個數據集的具體特徵描述可以參考這個文件。
本次我們實驗的目的主要是為了找出,當一個人在參加快速相親時,到底會有多高的機率能夠遇到自己心動的人併成功牽手。
在我們建模分析探索人性的祕密之前,讓我們先讀入數據,來看看我們的數據集長什麼樣。
import pandas as pd
df = pd.read_csv('Speed Dating Data.csv', encoding='gbk')
print(df.shape)
通過觀察,我們不難發現,在這短短的兩年中,這個實驗的小酒館經歷了8000多場快速相親的實驗。由此我們可以非常輕易的推斷出,小酒館的老闆應該賺的盆滿缽滿(大霧)
然後從數據的寬度來看,我們會發現一共有接近200個特徵。關於每個特徵的具體描述大家可以參考這篇文檔。然後我們再觀察數據的完整度,看看是否有缺失數據。
percent_missing = df.isnull().sum() * 100 / len(df)
missing_value_df = pd.DataFrame({
'column_name': df.columns,
'percent_missing': percent_missing
})
missing_value_df.sort_values(by='percent_missing')
通過以上代碼,我們不難發現,其實還有很多的特徵是缺失的。這一點在我們後面做分析和建模的時候,都需要關注到。因為一旦一個特徵缺失的數據較多,就會導致分析誤差變大或者模型過擬合/精度下降。看完數據的完整程度,我們就可以繼續往下探索了。
然後第一個問題就來了,在這8000多場的快速相親中,到底有多少場相親成功為參加的雙方找到了合適的伴侶的?帶著這個問題,我們就可以開始我們的第一個探索性數據分析。
# 多少人通過Speed Dating找到了對象
plt.subplots(figsize=(3,3), dpi=110,)
# 構造數據
size_of_groups=df.match.value_counts().values
single_percentage = round(size_of_groups[0]/sum(size_of_groups) * 100,2)
matched_percentage = round(size_of_groups[1]/sum(size_of_groups)* 100,2)
names = [
'Single:' + str(single_percentage) + '%',
'Matched' + str(matched_percentage) + '%']
# 創建餅圖
plt.pie(
size_of_groups,
labels=names,
labeldistance=1.2,
colors=Pastel1_3.hex_colors
)
plt.show()
從上邊的餅圖我們可以發現,真正通過快速相親找到對象的比率僅有16.47%。
然後我們就迎來了我們的第二個問題,這個比率和參加的人的性別是否有關呢?這裡我們也通過Pandas自帶的filter的方式
df[df.gender == 0]
來篩選數據集中的性別。通過閱讀數據集的文檔,我們知道0代表的是女生,1代表的是男生。然後同理,我們執行類似的代碼
# 多少女生通過Speed Dating找到了對象
plt.subplots(figsize=(3,3), dpi=110,)
# 構造數據
size_of_groups=df[df.gender == 0].match.value_counts().values # 男生只需要吧0替換成1即可
single_percentage = round(size_of_groups[0]/sum(size_of_groups) * 100,2)
matched_percentage = round(size_of_groups[1]/sum(size_of_groups)* 100,2)
names = [
'Single:' + str(single_percentage) + '%',
'Matched' + str(matched_percentage) + '%']
# 創建餅圖
plt.pie(
size_of_groups,
labels=names,
labeldistance=1.2,
colors=Pastel1_3.hex_colors
)
plt.show()
來找出女生和男生分別在快速相親中找到對象的機率的。
女生的機率:
男生的機率:
不難發現,在快速相親中,女生相比於男生還是稍微佔據一些優勢的。女生成功匹配的機率比男生成功匹配的機率超出了0.04。
然後第二個問題來了:是什麼樣的人在參加快速相親這樣的活動呢?真的都是大齡青年(年齡大於30)嘛?這個時候我們就可以通過對參加人群的年齡分佈來做一個統計分析。
# 年齡分佈
age = df[np.isfinite(df['age'])]['age']
plt.hist(age,bins=35)
plt.xlabel('Age')
plt.ylabel('Frequency')
不難發現,參加快速相親的人群主要是22~28歲的群體。這點與我們的預期有些不太符合,因為主流人群並不是大齡青年。接下來的問題就是,年齡是否會影響相親的成功率呢?和性別相比,哪個對於成功率的影響更大?這兩個問題在本文就先埋下一個伏筆,不一一探索了,希望閱讀文章的你能夠自己探索。
但是這裡可以給出一個非常好用的探索相關性的方式叫做數據相關性分析。通過閱讀數據集的描述,我已經為大家選擇好了一些合適的特徵去進行相關性分析。這裡合適的定義是指:1. 數據為數字類型,而不是字符串等無法量化的值。2.數據的缺失比率較低
date_df = df[[
'iid', 'gender', 'pid', 'match', 'int_corr', 'samerace', 'age_o',
'race_o', 'pf_o_att', 'pf_o_sin', 'pf_o_int', 'pf_o_fun', 'pf_o_amb',
'pf_o_sha', 'dec_o', 'attr_o', 'sinc_o', 'intel_o', 'fun_o', 'like_o',
'prob_o', 'met_o', 'age', 'race', 'imprace', 'imprelig', 'goal', 'date',
'go_out', 'career_c', 'sports', 'tvsports', 'exercise', 'dining',
'museums', 'art', 'hiking', 'gaming', 'clubbing', 'reading', 'tv',
'theater', 'movies', 'concerts', 'music', 'shopping', 'yoga', 'attr1_1',
'sinc1_1', 'intel1_1', 'fun1_1', 'amb1_1', 'attr3_1', 'sinc3_1',
'fun3_1', 'intel3_1', 'dec', 'attr', 'sinc', 'intel', 'fun', 'like',
'prob', 'met'
]]
# heatmap
plt.subplots(figsize=(20,15))
ax = plt.axes()
ax.set_title("Correlation Heatmap")
corr = date_df.corr()
sns.heatmap(corr,
xticklabels=corr.columns.values,
yticklabels=corr.columns.values)
通過上面這張圖這張相關性分析的熱力圖,我們可以先關注一些特別亮的和特別暗的點。比如我們可以發現,在 pf_o_att這個表示相親對象給出的外觀吸引力這個特徵上,和其他相親對象給出的評分基本都是嚴重負相關的,除了pf_o_fun這一特徵。由此我們可以推斷出兩個點:
1、大家會認為外觀更加吸引人的人在智商,事業心,真誠度上表現會相對較差。換句話說,可能就是顏值越高越浪
2、幽默風趣的人更容易讓人覺得外觀上有吸引力,比如下面這位幽默風趣的男士(大霧):
然後我們再看看我們最關注的特徵 match,和這一個特徵相關性比較高的特徵是哪幾個呢?不難發現,其實就是'attr_o','sinc_o','intel_o','fun_o','amb_o','shar_o'這幾個特徵,分別是相親對方給出的關於外觀,真誠度,智商,風趣程度,事業線以及興趣愛好的打分。接下來我們就可以根據這個來進行建模了。首先我們將我們的特徵和結果列都放到一個Dataframe中,然後再去除含有空值的紀錄。 最後我們再分為X和Y用來做訓練。當然分為X,y之後,由於我們在最開始就發現只有16.47%的參與場次中成功匹配了,所以我們的數據有嚴重的不均衡,這裡我們可以用SVMSMOTE來增加一下我們的數據量避免模型出現過度擬合。
# preparing the data
clean_df = df[['attr_o','sinc_o','intel_o','fun_o','amb_o','shar_o','match']]
clean_df.dropna(inplace=True)
X=clean_df[['attr_o','sinc_o','intel_o','fun_o','amb_o','shar_o',]]
y=clean_df['match']
oversample = imblearn.over_sampling.SVMSMOTE()
X, y = oversample.fit_resample(X, y)
# 做訓練集和測試集分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0, stratify=y)
數據準備好之後,我們就可以進行模型的構建和訓練了。通過以下代碼,我們可以構建一個簡單的邏輯迴歸的模型,並在測試集上來測試。
# logistic regression classification model
model = LogisticRegression(C=1, random_state=0)
lrc = model.fit(X_train, y_train)
predict_train_lrc = lrc.predict(X_train)
predict_test_lrc = lrc.predict(X_test)
print('Training Accuracy:', metrics.accuracy_score(y_train, predict_train_lrc))
print('Validation Accuracy:', metrics.accuracy_score(y_test, predict_test_lrc))
我們可以看到結果為0.83左右,這樣我們就完成了一個預測在快速相親中是否能夠成功配對的機器學習模型。針對這個模型,數據科學老司機我還專門製作了一個小遊戲頁面,來測試你的相親戰鬥力指數。 同時也歡迎你加入我們的DSW用戶交流群,和我們一起交流/探索更多好玩又實用的機器學習/深度學習案例。