kaggle再一次入門~經典入門級競賽~Titanic
題外話:想著更早的接觸到資料競賽,就可以更早的學到理論,練到技術,拿到名次,賺得獎金~功利心太重了,屢屢開始入門比賽,屢屢不了了之。加入俱樂部,發現大家本科就知道這些,已經參加了各種資料科學競賽,並且有了不小的學習成就和心得體會,當然還有白花花的銀子,然而,我沒有在第一時間找到小白同學共同學習,沒有抱緊大佬大腿努力學習,而是打算自己慢慢摸爬滾打入門,再找大家交流。結果自己沒有摸出門道,提前放棄,一起的小夥伴也在通往大佬的路上越走越遠,我還停在原地。再後來,瞭解到DataWhale這個神奇的開源組織,從街景字元識別開始,研究水哥、魚佬給出的baseline,還是我不夠努力,對於我而言,能弄懂baseline就挺費勁的了,在這個基礎上,增加特徵,我無從下手,也沒有請教別人。歸根結底,都是我懶惰,加急功近利的性子導致的,太害怕失敗,害怕困難,而選擇就此止步,可我又不甘如此,經常做著自我鬥爭。年輕人終歸是要奮鬥的,要拿出年輕人的朝氣,在此替過去的自己對現在的自己說聲抱歉。
在有了一定基礎之後,再次看泰坦尼克號這個題目,覺得好簡單。然而,還是有很多工作需要做,從資料分析,到如何建立一個有效的模型,再到調參分析等,都是新手需要鑽研的。以下是處理資料分析比賽的一個基本思路:
1 分析賽題
直譯:泰坦尼克號的沉沒是歷史上最臭名昭著的沉船事件之一。1912年4月15日,被廣泛認為是永不沉沒的皇家郵輪泰坦尼克號在處女航中與冰山相撞後沉沒。不幸的是,船上沒有足夠的救生艇運載所有乘客,導致2224名乘客和船員中有1502人死亡。雖然生存有一些運氣的因素,但似乎某些群體的人比其他人更有可能存活下來。在這次挑戰中,我們要求你建立一個預測模型來回答以下問題:什麼樣的人更有可能存活?使用乘客資料(如姓名、年齡、性別、社會經濟等級等)。
首先分析一下賽題,賽題定位是一個二分類問題,任務是通過train.csv
(已經標註label的乘客資訊)來預測test.csv
(未標註label的乘客資訊)中的label,其中label就是乘客是否存活,存活標記為1,未存活標記為0。然後我們需要將預測出來的結果存入submit.csv
中,包括乘客id
和label
即可。
Goal
It is your job to predict if a passenger survived the sinking of the Titanic or not.
For each in the test set, you must predict a 0 or 1 value for the variable.
Metric
Your score is the percentage of passengers you correctly predict. This is known as accuracy.
A
c
c
u
r
a
c
y
=
(
T
P
+
T
N
)
/
(
T
P
+
T
N
+
F
P
+
F
N
)
w
h
e
r
e
:
T
P
=
T
r
u
e
p
o
s
i
t
i
v
e
;
F
P
=
F
a
l
s
e
p
o
s
i
t
i
v
e
;
T
N
=
T
r
u
e
n
e
g
a
t
i
v
e
;
F
N
=
F
a
l
s
e
n
e
g
a
t
i
v
e
Accuracy = (TP + TN)/(TP + TN + FP + FN)\\ where: TP = True positive; FP = False positive; TN = True negative; FN = False negative
Accuracy=(TP+TN)/(TP+TN+FP+FN)where:TP=Truepositive;FP=Falsepositive;TN=Truenegative;FN=Falsenegative
Submission File Format
You should submit a csv
file with exactly 418 entries plus a header row. Your submission will show an error if you have extra columns (beyondPassengerId
and Survived
) or rows.
The file should have exactly 2 columns:
PassengerId
(sorted in any order)- Survived (contains your binary predictions: 1 for survived, 0 for deceased)
2 分析資料:
資料集欄位解釋:
pclass: A proxy for socio-economic status (SES)社會經濟地位的代表
1st = Upper
2nd = Middle
3rd = Lower
age: Age is fractional if less than 1. If the age is estimated, is it in the form of xx.5
sibsp: The dataset defines family relations in this way...
Sibling = brother, sister, stepbrother, stepsister
Spouse = husband, wife (mistresses and fiancés were ignored)
parch: The dataset defines family relations in this way...
Parent = mother, father
Child = daughter, son, stepdaughter, stepson
Some children travelled only with a nanny(保姆), therefore parch=0 for them.
2.1 資料集統計分析:
在kaggle
中,賽題的資料都在../input
目錄下存放著,我們可以通過os.walk(dir_path)
的方式遍歷到目錄dir_path
中的所有檔名,然後將根目錄和檔名拼接起來就是資料檔案的絕對路徑了。
import os
for dirname, _, filenames in os.walk('/kaggle/input'):
for filename in filenames:
print(os.path.join(dirname, filename))
# /kaggle/input/titanic/train.csv
# /kaggle/input/titanic/test.csv
# /kaggle/input/titanic/gender_submission.csv
知道資料集地址之後,使用pandas
讀取資料集,pandas
進行資料分析的一些常用方法可以自己簡單瞭解一下。pandas
讀取的檔案結果是DataFrame
型別,即二維表格型別;head()
返回的是前幾條資料,tail()
返回的後幾行資料,括號中可以填寫你想檢視的行數,預設是5。對於較大的資料集,我一般還會列印train_data.shape
,train_data.columns
檢視資料大小和列名,方便分析每一列的屬性。還可以通過train_data.describe()
表示對資料集的統計性分析,詳細介紹看這裡。.value_counts()
表示對每一個屬性不同取值的計數;.count()
表示每一個屬性的非零取值的計數,即value_counts()
的和
train_data = pd.read_csv("/kaggle/input/titanic/train.csv")
print(train_data.shape,train_data.columns)
"""
((891, 12), Index(['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp', 'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked'], dtype='object'))
"""
train_data.head() # 圖1
train_data.describe() # 圖2,count表示非空值個數,後面的意思分別是均值、方差、最大最小值、百分位數
檢視每一列的取值範圍,train_data['Pclass'].unique()
可以得到array([3, 1, 2])
,即乘客的階級為三個等級。用.value_counts()
可以得到每一個取值的樣本數,通過檢視len(train_data[i].unique())
得到不同屬性的取值個數。同理,依次對每一個屬性進行分析:
for i in train_data.columns:
print(i,len(train_data[i].unique()))
PassengerId 891 唯一性
Survived 2 {1,0}表示survive/die
Pclass 3 {1 = 1st, 2 = 2nd, 3 = 3rd}表示社會階層
Name 891 唯一性
Sex 2 {male,female}表示男/女
Age 89 {0.0,...,80}表示年齡
SibSp 7 兄弟姐妹/配偶
Parch 7 父母/孩子
Ticket 681 船票號
Fare 248 票價
Cabin 148 客艙號(房間號)
Embarked 4 {C = Cherbourg, Q = Queenstown, S = Southampton}表示出發港(上船地點)
for i in train_data.columns:
print(train_data[i].value_counts(),'\n')
Name: PassengerId, Length: 891, dtype: int64
0 549
1 342
Name: Survived, dtype: int64
3 491
1 216
2 184
Name: Pclass, dtype: int64
Name: Name, Length: 891, dtype: int64
male 577
female 314
Name: Sex, dtype: int64
24.00 30
22.00 27
18.00 26
19.00 25
30.00 25
..
55.50 1
70.50 1
66.00 1
23.50 1
0.42 1
Name: Age, Length: 88, dtype: int64
0 608
1 209
2 28
4 18
3 16
8 7
5 5
Name: SibSp, dtype: int64
0 678
1 118
2 80
5 5
3 5
4 4
6 1
Name: Parch, dtype: int64
CA. 2343 7
347082 7
1601 7
3101295 6
CA 2144 6
..
3101264 1
226875 1
330980 1
315096 1
28664 1
Name: Ticket, Length: 681, dtype: int64
8.0500 43
13.0000 42
7.8958 38
7.7500 34
26.0000 31
..
8.4583 1
9.8375 1
8.3625 1
14.1083 1
17.4000 1
Name: Fare, Length: 248, dtype: int64
G6 4
B96 B98 4
C23 C25 C27 4
E101 3
C22 C26 3
..
D28 1
D19 1
C111 1
C118 1
D6 1
Name: Cabin, Length: 147, dtype: int64
S 644
C 168
Q 77
Name: Embarked, dtype: int64
可以看到,以上欄位中,PassengerId
和Name
都具有唯一性,Survived
取值{0,1}
,其餘的欄位意思請看上面程式碼輸出中標註。
2.2 對於缺失值的處理:
檢視是否有缺失值,對於缺失值的處理,其一,是用某種值去填充;其二,若該列不太重要,可以直接刪除該列。在describe()
的描述中,可以看到年齡是714個非空值,有部分缺失;其餘字元型別的欄位沒有顯示,此處再次檢視一下他們的缺失值:
for i in train_data.columns:
print(i,'\n',train_data[i].count())
# Age 714; Cabin 204; Embarked 889
可以看到船艙號Cabin
缺失佔比較大,年齡Age
和出發港口Embarked
都有部分缺失;其中我認為船艙號和社會階級Pclass
是分不開的,且由於cabin
取值類別太多,對缺失值不容易填充,因此直接刪除該屬性,暫時不做考慮。
其次,乘客ID和票號我覺得不具有參考價值,因此選擇刪除列;name中包含的資訊較多,包括Mr/Mrs/master
等會蘊含一些資訊,但是性別和票價並無缺失,應該可以代替這個屬性,因此也刪除該列。
目前,剩餘有缺失的屬性只有年齡和港口,若缺失值在總資料集佔比不大的話,認為是壞樣本,可以直接將有缺失值的行刪除。age有將近20%的缺失值,embarked有兩個缺失值。暫時先不處理,下面參考的博文直接刪掉著20%,我覺得著資料量挺大的,怎麼能瞎刪呢?
2.3 測試集類比分析
同樣步驟對測試集進行分析,資料集為(418,11)
,年齡的非缺失值有332條,同樣缺失率為20%左右;fare有1條缺失值;缺失率最大的仍然是cabin
僅有91條,缺失率在78%左右。測試集是不可以刪除行的,因此對fare和age進行填充,將cabin這一列去掉。如何填充需要對資料進行統計分析,如下是我將不同屬性的取值較多的值貼上的結果。同樣是參考部落格說fare的眾數是7.75,因此直接用該值填充,我覺得眾數並不明顯,以下四個取值數差不多
#處理一下測試集裡的缺失值,測試集的缺失資料不能刪
#處理Fare,先看一下分佈,發現明顯有個眾數非常突出,且訓練集和測試集眾數接近:
test_data['Fare']=test_data['Fare'].fillna(test_data['Fare'].dropna().mode()[0])
3 218
1 107
2 93
Name: Pclass, dtype: int64
male 266
female 152
Name: Sex, dtype: int64
24.0 17
21.0 17
22.0 16
30.0 15
18.0 13
Name: Age, Length: 79, dtype: int64
0 283
1 110
2 14
4 4
3 4
Name: SibSp, dtype: int64
0 324
1 52
2 33
Name: Parch, dtype: int64
7.7500 21
26.0000 19
8.0500 17
13.0000 17
Name: Fare, Length: 169, dtype: int64
S 270
C 102
Q 46
Name: Embarked, dtype: int64
2.3 資料模式探索/猜測
根據上面資料的統計結果,訓練集中存活率為38%
,男女比例為:577:314
,
根據情境,當時看電影,女人和小孩先上船,由於年齡Age
資訊缺失較大,我們先假設所有女性female
都存活了,為了驗證我們的假設是否合理,因此,下面計算女性存活的比例:
women = train_data.loc[train_data.Sex == 'female']["Survived"] # 獲得性別為“female”倖存者資料
rate_women = sum(women)/len(women) # 計算女性倖存者比率
print("ratio of women who survived:", rate_women) # 0.7420382165605095,同理,男性存活率0.1889081456
這就為我們提供了一個思路,在分析資料的時候,我們可以按照類別分析不同屬性值所佔的比例,檢視樣本分佈是否均勻,分析出來對類別影響較大的特徵。
train_data = train_data.drop(columns=['PassengerId','Cabin','Ticket','Name'])
for column in train_data.columns:
print(train_data.groupby('Survived')[column].value_counts()) # Series型別,[0]為died,[1]為survived
Survived Survived
0 0 549
1 1 342
Name: Survived, dtype: int64
Survived Pclass
0 3 372
2 97
1 80
1 1 136
3 119
2 87
Name: Pclass, dtype: int64
Survived Sex
0 male 468
female 81
1 female 233
male 109
Name: Sex, dtype: int64
Survived Age
0 21.0 19
28.0 18
18.0 17
25.0 17
19.0 16
..
1 43.0 1
47.0 1
53.0 1
55.0 1
80.0 1
Name: Age, Length: 142, dtype: int64
Survived SibSp
0 0 398
1 97
2 15
4 15
3 12
8 7
5 5
1 0 210
1 112
2 13
3 4
4 3
Name: SibSp, dtype: int64
Survived Parch
0 0 445
1 53
2 40
4 4
5 4
3 2
6 1
1 0 233
1 65
2 40
3 3
5 1
Name: Parch, dtype: int64
Survived Fare
0 8.0500 38
7.8958 37
13.0000 26
7.7500 22
26.0000 16
..
1 82.1708 1
83.4750 1
106.4250 1
108.9000 1
247.5208 1
Name: Fare, Length: 330, dtype: int64
Survived Embarked
0 S 427
C 75
Q 47
1 S 217
C 93
Q 30
Name: Embarked, dtype: int64
分析每一個欄位:
- 階級: 1 s t : 2 n d : 3 r d = 216 : 184 : 491 ≈ 2 : 2 : 5 1st:2nd:3rd=216:184:491\approx 2:2:5 1st:2nd:3rd=216:184:491≈2:2:5,死亡階級人數比例: 1 s t : 2 n d : 3 r d = 80 : 97 : 372 ≈ 1 : 1 : 4 1st:2nd:3rd=80:97:372\approx 1:1:4 1st:2nd:3rd=80:97:372≈1:1:4,生存階級人數比例: 1 s t : 2 n d : 3 r d = 136 : 87 : 119 ≈ 1.5 : 1 : 1.3 1st:2nd:3rd=136:87:119\approx 1.5:1:1.3 1st:2nd:3rd=136:87:119≈1.5:1:1.3,每一個階級的生還比例: 3 r d = 24.24 % ; 2 n d = 47.28 % ; 1 s t = 62.96 % 3rd=24.24\%;2nd=47.28\%;1st=62.96\% 3rd=24.24%;2nd=47.28%;1st=62.96%,看來窮人生還比例最低。那是否窮人裡面女性和兒童人數少呢?
- 年齡:生還的人年齡分佈
import matplotlib.pyplot as plt
age_survived = train_data.groupby('Survived')['Age'].value_counts()[1]
plt.bar(age_survived.index,age_survived)
- 兄弟姐妹數:可以看出來,少的生還率高些,人數太多的生還率低
sib_sur_cnt = train_data.groupby('Survived')['SibSp'].value_counts()[1]
sib_all_cnt = train_data['SibSp'].value_counts()
for i in sib_all_cnt.index:
if i == 5 or i == 8:
sib_sur_cnt[i]=0
print('sibling number:',i,' survived rate:',sib_sur_cnt[i]/sib_all_cnt[i])
sibling number: 0 survived rate: 0.34539473684210525
sibling number: 1 survived rate: 0.5358851674641149
sibling number: 2 survived rate: 0.4642857142857143
sibling number: 4 survived rate: 0.16666666666666666
sibling number: 3 survived rate: 0.25
sibling number: 8 survived rate: 0.0
sibling number: 5 survived rate: 0.0
- 父母孩子:人數太多的生還率低
pc_sur_cnt = train_data.groupby('Survived')['Parch'].value_counts()[1]
pc_all_cnt = train_data['Parch'].value_counts()
# print(pc_all_cnt.index,pc_sur_cnt.index)
for i in pc_all_cnt.index:
if i == 4 or i == 6:
pc_sur_cnt[i]=0
print('parent-child number:',i,' survived rate:',pc_sur_cnt[i]/pc_all_cnt[i])
parent-child number: 0 survived rate: 0.34365781710914456
parent-child number: 1 survived rate: 0.5508474576271186
parent-child number: 2 survived rate: 0.5
parent-child number: 5 survived rate: 0.2
parent-child number: 3 survived rate: 0.6
parent-child number: 4 survived rate: 0.0
parent-child number: 6 survived rate: 0.0
- Fare
train_data.groupby('Pclass')['Fare'].sum()/train_data.groupby('Pclass')['Survived'].count()
# Pclass 各階級人均車票錢: 1 84.154687; 2 20.662183; 3 13.675550
- 上車站:覺得這個影響因素本身就不大
parent-child number: S survived rate: 0.33695652173913043
parent-child number: C survived rate: 0.5535714285714286
parent-child number: Q survived rate: 0.38961038961038963
因此,在以上分析過程中,生還可能性與階級、性別、年齡、家人數都有關係,只是關係強弱還未分析,目測與上車口關係不大,車票價錢其實在階級上應該有所反應,應該聯合起來分析一下。
然而,手動提取特徵非常受限;因此,我們採用機器學習的方式進行自動選取特徵,首先要學習的是“隨機森林”,森林由多棵“決策樹”構成,每一棵決策樹會得到一個結果,最後採用“投票法”選擇票數最高的特徵作為結果。(一般的資料科學比賽最初都用的是樹模型,比如較火的lightGBM,XgBoost,CatBoost等)
3 隨機森林
下面是’咖金’那裡拷來的程式碼,直接用sklearn封裝好的庫好容易,但還是要深入學習原理,才能更好地利用它:
from sklearn.ensemble import RandomForestClassifier # 匯入隨機森林模組
# 獲取用於預測的X,y
y = train_data["Survived"]
# 和上面分析的結果一致,年齡缺失較多,從圖上分析,可能也沒那麼重要
features = ["Pclass", "Sex", "SibSp", "Parch"]
X = pd.get_dummies(train_data[features])
X_test = pd.get_dummies(test_data[features])
# 訓練模型
model = RandomForestClassifier(n_estimators=100, max_depth=5, random_state=1)
model.fit(X, y)
predictions = model.predict(X_test)
# 輸出預測並儲存為本地檔案
output = pd.DataFrame({'PassengerId': test_data.PassengerId, 'Survived': predictions})
output.to_csv('my_submission.csv', index=False)
print("Your submission was successfully saved!")
pd.get_dummies():在使用隨機森林時,需要將非數值列轉換成數值型或者one-hot編碼,這個方法就是將feature中的Sex進行了onehot編碼(或者可以用sklearn
的sklearn.preprocessing.OneHotEncoder
)
4 XGboost
5 參考博文
後記:
想把思路寫的清楚一些,寫完之後發現有些繁瑣了,不夠有條理,湊活能看,也是學習的過程,加油!
相關文章
- 【Kaggle入門級競賽top5%排名經驗分享】— 分析篇
- 【Kaggle入門級競賽top5%排名經驗分享】— 建模篇
- 演算法競賽入門經典訓練指南 pdf演算法
- 《Flutter 入門經典》之“Flutter 入門 ”Flutter
- Kaggle機器學習入門實戰 -- Titanic乘客生還預測機器學習
- 博弈論經典模型解析(入門級)模型
- csharp入門經典CSharp
- Python入門經典案例一Python
- Unix 入門經典 筆記筆記
- Kaggle八門神器(一):競賽神器之XGBoost介紹
- 經典加密演算法入門-RSA加密演算法
- 聊聊經典機器學習入門機器學習
- Kaggle入門之房價預測
- 演算法競賽C++快速入門演算法C++
- C語言入門經典(第5版)C語言
- Go語言入門經典第18章Go
- 嵌入式開發 ARM入門經典
- Python 入門之經典函式例項(二)Python函式
- Kaggle 入門並實戰房價預測
- 競爭條件入門
- Spark入門(三)--Spark經典的單詞統計Spark
- JavaScript函數語言程式設計入門經典JavaScript函數程式設計
- 入門級前端教程前端
- grafana初級入門Grafana
- Python入門教程之Python經典面試題(附答案)Python面試題
- 十大Python經典面試題,入門必知!Python面試題
- ACM演算法競賽_快速入門v0.1(施工中)ACM演算法
- 入門入門入門 MySQL命名行MySql
- 第 8 場 小白入門賽
- Python程式設計入門——基礎語法詳解(經典)Python程式設計
- 大資料hadoop 新手快速入門經典視訊教程大資料Hadoop
- Python網路程式設計(基礎總結入門經典)Python程式設計
- 大話PM 談談產品入門的經典語錄
- HTTPS入門級總結HTTP
- Java註解(入門級)Java
- 入門級的Git操作Git
- 何入CTF的“門”?——所謂入門就是入門
- 如何入CTF的“門”?——所謂入門就是入門