泰坦尼克号是英国白星航运公司下的一艘奥林匹克级邮轮,号称永不沉没,然而在1912年4月14日却与冰山相撞,沉没水中。2224 名船员及乘客中,有 1517 人丧生,是一次伤亡惨重的海难。
而泰坦尼克号数据分析比赛是 Kaggle 上的一个比赛,通过训练集和测试机来预测乘客的生还情况。
- Python 3.6
- WSL ubuntu 18.04
- VS Code
- Tensorflow 1 / Tensorflow 2
首要目的是将数据读取到内存中,pandas
库可以方便的对数据进行读取。
1
2
3
| import pandas as pd
# /mnt/e/python-learn/data/titanic/train.csv
titanic_test_data = pd.read_csv(r'/mnt/e/python-learn/data/titanic/train.csv')
|
数据清洗在数据分析中占有很重要的一部分。通过下面代码我们可以知道读入数据的数据结构。
1
| titanic_test_data.info()
|
当执行该代码的时候,会打印出下面的结构。
<class ‘pandas.core.frame.DataFrame’>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
PassengerId 891 non-null int64
Survived 891 non-null int64
Pclass 891 non-null int64
Name 891 non-null object
Sex 891 non-null object
Age 714 non-null float64
SibSp 891 non-null int64
Parch 891 non-null int64
Ticket 891 non-null object
Fare 891 non-null float64
Cabin 204 non-null object
Embarked 889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB
通过观察可以发现,部分数据是丢失的,比如说 Age、Cabin、Embarked。
这里可以看出所有的属性字段,但是有一些字段对于我们的研究是无关的。
PassgengerId
该属性对于乘客是否被救是无关的。
Name
,姓名可以说对我们的研究是不太相关的,但是也不能说完全不相关,比如说我们可以从姓名中找到该乘客的家族等。这里我们可以选择把他剔除掉。
Ticket
该字段每个值都是不同的,不会对预测结果产生影响。
Cabin
值缺失太多,我们无法直接去使用
所以我们先把这些无用值进行剔除。
1
2
| titanic_test_data = titanic_test_data[['Survived', 'Pclass',
'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']]
|
下面就要对这些缺失值进行补全。对缺失值进行补全的方法有很多:
忽略元组
人工填写缺失值
使用一个全局常量填充缺失值
使用属性的中心度量填充缺失值
使用与给定元组属同一类的所有样本的属性均值或者中位数
使用最有可能的值填充缺失值
这里我采用了使用第四点,使用属性的中心度量填充缺失值。
使用平均值对数据进行填充。
1
2
3
| # Age
age_median = titanic_train_data['Age'].mean()
titanic_train_data['Age'] = titanic_train_data['Age'].fillna(age_median)
|
可以看出来,有些属性的值是字符串类型,这些类型对于计算机来说是操作不利的,要将字符串类型改为数值类型。
Sex
这一栏中,给定的值为 male 和 female 两个值,我们可以将它们转化为 0 与 1。
1
| titanic_train_data['Sex'] = [ 1 if x == 'male' else 0 for x in titanic_train_data.Sex]
|
还有 embarked 也可以进行调整,将字符 C
,S
,Q
进行转换。
1
2
3
| titanic_train_data['Embarked'][titanic_train_data['Embarked'] == 'S'] = 1
titanic_train_data['Embarked'][titanic_train_data['Embarked'] == 'C'] = 2
titanic_train_data['Embarked'][titanic_train_data['Embarked'] == 'Q'] = 3
|
最后将 label 数据分离出来。
1
2
3
| y_data = titanic_train_data
titanic_train_data = titanic_train_data[['Pclass','Sex', 'Age', 'SibSp','Parch', 'Fare', 'Embarked']]
y_label = y_data[['Survived']]
|
可以用上述方法处理测试集数据。
对 Embarked 进行补全,我们采取出现频率最高的进行补全。
1
2
3
| embarked_value = titanic_train_data['Embarked'].value_counts().index[0]
titanic_train_data['Embarked'] = titanic_train_data['Embarked'].fillna(
embarked_value)
|
创建 Tensor。采用线性回归,$ y=\omega x^{\tau } + b $ 。
在数据处理的时候,只留下了7列数据来供我们使用,而最后的结果值只有一个。所以我们对数据进行定义的时候要明白我们的定义的形状。
1
2
3
4
| y = tf.placeholder(name='y', shape=[None, 1], dtype=tf.float32)
x = tf.placeholder(name='x', shape=[None, 7], dtype=tf.float32)
w = tf.Variable(tf.random_uniform([1, 7]), name='w', dtype=tf.float32)
b = tf.Variable(tf.random_uniform([1]), name='b')
|
Tensor 定义完成后,需要进行对式子进行表达。
1
| z = tf.matmul(w, tf.transpose(x)) + b
|
损失函数是对模型评估的重要方法,这里采用交叉熵进行评估。
1
2
3
| loss = tf.nn.sigmoid_cross_entropy_with_logits(
labels=y_label_data_array_shape , logits=z)
loss = tf.reduce_mean(loss)
|
通过优化器来对函数进行求解。这里采用 AdagradOptimizer
算法进行计算,学习率初值为 0.5 。
1
| optimizer = tf.train.AdagradOptimizer(0.5).minimize(loss=loss)
|
我选择了 epoch
为 10000,进行 10000 轮的迭代。同时要对 y_label
进行一下转换,保证形状的正确性。
1
2
3
| epoch = 10000
y_label_data_array_shape = tf.reshape(y_label, [1, 891])
y_label_data_array_shape = tf.to_float(y_label_data_array_shape)
|
每次都将所有的值进行投喂,进行结果训练,并没100次将值进行打印输出,查看当前计算的损失值。
最后将输出的值进行划分为 0 和 1 .
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
for i in range(epoch):
feed = {x: titanic_train_data, y: y_label}
sess.run(optimizer, feed_dict=feed)
if i % 100 == 0:
loss_value = sess.run(
[loss], feed_dict=feed)
print(i//100 + 1, ' loss =>', loss_value)
pred = sess.run(tf.nn.sigmoid(z) , feed_dict={x: titanic_test_data})
sur = [1 if x > 0.5 else 0 for x in pred.flatten()]
submission = pd.DataFrame({
'PassengerId': original_test_data['PassengerId'],
'Survived': sur
})
submission.to_csv('titanic-submission.csv', index=False)
|
这里通过测试集的正确率是 0.78 。
算法还在不断完善。
在国庆期间, Google 发布了 Tensorflow 2。相较于 tf1, tf2 做了很多更改,更加的推荐使用 keras 来进行模型的搭建,也更改了很多 API,比如说不再需要 PlaceHolder
,运行不需要再进行 Session
管理,这些更改都极大的我们使用和上手的难度,使 tf 更加易用。
下面贴出 tf2 的兼容代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
| tf.compat.v1.disable_eager_execution()
y = tf.compat.v1.placeholder(name='y', shape=[None,1], dtype=tf.float32)
x = tf.compat.v1.placeholder(name='x', shape=[None, 7], dtype=tf.float32)
w = tf.Variable(tf.random.normal([1, 7]), name='w', dtype=tf.float32)
b = tf.Variable(tf.random.normal([1]), name='b')
y_label_tensor = tf.convert_to_tensor(y_label,dtype=tf.float32,dtype_hint=True)
y_label_data_array_shape = tf.reshape(y_label_tensor, [1, 891])
y_label_data_array_shape = tf.cast(y_label_data_array_shape,dtype=tf.float32)
# z 为预测值
z = tf.matmul(w, tf.transpose(x)) + b
# sigmoid
# 交叉熵
loss = tf.nn.sigmoid_cross_entropy_with_logits(
labels=y_label_data_array_shape , logits=z)
loss = tf.reduce_mean(loss)
optimizer = tf.compat.v1.train.AdagradOptimizer(0.1).minimize(loss=loss)
epoch = 10000
loss_value_in_plt = []
with tf.compat.v1.Session() as sess:
sess.run(tf.compat.v1.global_variables_initializer())
feed = {x: titanic_train_data, y: y_label}
for i in range(epoch):
sess.run(optimizer, feed_dict=feed)
if i % 100 == 0:
loss_value = sess.run(
[loss], feed_dict=feed)
loss_value_in_plt.append(loss_value)
print(i//100 + 1, ' loss =>', loss_value)
pred = sess.run(tf.nn.sigmoid(z) , feed_dict={x: titanic_test_data})
sur = [1 if x > 0.5 else 0 for x in pred.flatten()]
submission = pd.DataFrame({
'PassengerId': original_test_data['PassengerId'],
'Survived': sur
})
submission.to_csv('titanic-submission.csv', index=False)
print("训练完毕")
|
然而,tf2 更加推荐使用 keras。下面是采用 Keras 进行的训练代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| x = titanic_train_data
y = y_label
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(1,input_shape=(7,),activation='sigmoid'))
model.compile(optimizer='adam',loss='binary_crossentropy',metrics=['acc'])
history = model.fit(x,y,epochs=epoch,batch_size=50,verbose=0)
l = model.predict(titanic_test_data)
survived = [1 if x > 0.5 else 0 for x in l]
submission = pd.DataFrame({
'PassengerId': original_test_data['PassengerId'],
'Survived': survived
})
submission.to_csv('titanic-submission.csv', index=False)
|