Python数据科学实践
- 2020 年 2 月 9 日
- 筆記
本文使用一个完整的例子来理解python数据科学,例子用到numpy/pandas/matplotlib/keras这些和数据科学相关的python库,实现数据预处理、分析、时间序列模型训练及预测一整个流程。最终目的是帮助理解python数据科学的一般过程,以及熟悉python相关科学计算库的使用。
1、构造实验用数据
使用numpy构建一个班级5位同学N次数学考试的成绩, 同学成绩需要有上升趋势、下降趋势、平稳、严重抖动。
import numpy as np import pandas as pd import matplotlib.pyplot as plt np.random.seed(1) N = 100
1.1 构造第1位同学成绩
# 第一位同学, 成绩平平大约在85分左右, 比较稳定 rand1 = np.random.normal(0, 1, N) avg1 = 85 std1 = np.rint(avg1 + rand1) plt.plot(std1) plt.ylim(50, 100) plt.show()

1.2 构造第2位同学成绩
# 第二位同学, 成绩优秀且稳步提高 rand2 = np.random.normal(0, 1, N) avg2 = 90 trend2 = np.linspace(0, 10, N) std2 = np.rint(avg2 + rand2 + trend2) # 故意产出可能出现异常值的情况,后面数据预处理统一处理 std2[10] = np.nan std2[13] = np.nan # 有两次考试因病缺席

1.3 构造第3位同学成绩
# 第三位同学, 成绩较好但波动较大 rand3 = np.random.normal(0, 5, N) avg3 = 88 std3 = np.rint(avg3 + rand3)

1.4 构造第4位同学成绩
# 第四位同学, 屌丝逆袭一路高歌 rand4 = np.random.normal(0, 2, N) avg4 = 55 trend4 = np.linspace(0, 50, N) std4 = np.rint(avg4 + rand4 + trend4)

1.5 构造第5位同学成绩
# 第五位同学, 不断努力,但受某些外部因素干扰,成绩上升且具有周期性 rand5 = np.random.normal(0, 1, N) avg5 = 72 trend5 = np.linspace(0, 20, N) period5 = 3 * np.sin(np.linspace(0, 100, N)) std5 = np.rint(avg5 + rand5 + trend5 + period5)

1.6 多子图显示多个同学的成绩曲线
# 多子图显示多个同学的成绩曲线 fig, ax = plt.subplots(2, 3, sharex='col', sharey='row', figsize=(20, 10)) plt.ylim(50, 110) total = {'student1': std1, 'student2': std2, 'student3': std3, 'student4': std4, 'student5': std5} keys = list(total.keys()) index = 0 for i in range(2): for j in range(3): try: key = keys[index] except Exception as e: pass else: std_score = total[key] ax[i, j].plot(std_score, label=key) ax[i, j].legend() index += 1

1.7 数据写入文件保存
最后将上面构造的实验数据通过pandas的to_csv函数写入到文件中保存。
df = pd.DataFrame({ 'student1': std1, 'student2': std2, 'student3': std3, 'student4': std4, 'student5': std5}) df.to_csv('student_score_raw.csv')
2、数据分析及预处理
使用pandas对实验数据进行一些处理。
2.1 使用pandas读取实验数据
df = pd.read_csv('student_score_raw.csv', index_col=0) # 第一例作为行索引,默认使用第一行作为列索引 df.head()

2.2 查看各个同学成绩的概况
# 查看统计信息,可以看到哪个同学波动较大,哪个同学平均分较高等,却很难像曲线图那样直观看出各个同学的分数趋势 df.describe()

2.3 剔除脏数据
df.plot(figsize=(10, 5))

# 将超过100分的数据设置为100分满分 df[df > 100] = 100 # 处理缺失值, 用缺失值前面的有效值从前往后填补 df = df.fillna(method='ffill', axis=0) df.plot(figsize=(10, 5))

# 通过曲线可以直观看出: # student1: 成绩一般,且很稳定 # student2: 成绩优秀,且稳步上升 # studeng3: 成绩一般,且波动很大 # student4: 屌丝逆袭,一路高歌 # student5: 一直进步,但具有一些周期性 # 和当初的数据设计吻合 df.to_csv('student_score.csv')
3、成绩预测
抽取一个同学的成绩序列, 使用深度学习库keras,训练预测模型, 预测下一次的分数,并评估预测效果。
# 使用keras做预测 import math from keras.models import Sequential from keras.layers import Dense from keras.layers import LSTM from sklearn.metrics import mean_squared_error
3.1 获取成绩序列
def gen_data(): '''生产用于做预测的数据''' df = pd.read_csv( 'student_score.csv', index_col=0, header=0) return df['student5'] s = gen_data() # 抽取student5的同学成绩做模型训练, 预测该同学未来的成绩 s.plot(figsize=(10, 5))

3.2 对数据进行归一化处理
from sklearn.preprocessing import MinMaxScaler def preprocessing_scale(data): '''对数据进行归一化。 args: data: 时序数据原始数据数组 returns: dataset: 经过归一化后的时序数据 scaler: 缩放 ''' scaler = MinMaxScaler(feature_range=(0, 1)) dataset = np.array(data) dataset = np.reshape(dataset, (dataset.shape[0], 1)) dataset = dataset.astype('float32') dataset = scaler.fit_transform(dataset) return dataset, scaler
3.3 将数据划分成训练集和测试集
def preprocessing_split(dataset): '''对数据划分训练数据和测试数据。 args: dataset: 时序数据数组 returns: 四元祖,(dataset, train, test, scaler) dataset: 经过reshape和最大最小缩放后的时序数据 train: 划分出来的训练集 test: 划分出来的测试集 scaler: 数据缩放对象 ''' train_size = int(len(dataset) * 0.66) test_size = len(dataset) - train_size train, test = dataset[0:train_size, :], dataset[train_size:, :] return train, test train, test = preprocessing_split(dataset) print(train.shape, test.shape) # (66, 1) (34, 1)
3.4 构造可输入LSTM模型的数据
对自回归数据做滑动窗口构造训练用的特征和标签数据。
def create_dataset(dataset, look_back=1): '''构造用于LSTM训练的数据。 args: dataset: 时序数据数组 look_back: 步长值 returns: 元组,(特征x数组,标签y数组) ''' dataX, dataY = [], [] for i in range(len(dataset)-look_back): a = dataset[i: (i+look_back), 0] dataX.append(a) dataY.append(dataset[i+look_back, 0]) return np.array(dataX), np.array(dataY) x, y = create_dataset(train, 3)
3.5 构建LSTM模型
def create_lstm_model(look_back, predict_steps=1): '''构建lstm模型 传入步长值,构建简单的lstm模型并返回。 args: look_back: 步长值 returns: model: keras的lstm模型 ''' model = Sequential() model.add(LSTM(32, input_shape=(1, look_back))) model.add(Dense(predict_steps)) model.compile(loss='mean_squared_error', optimizer='adam') return model
3.6 模型训练
def model_fit(model, train_x, train_y): '''训练模型''' model.fit(train_x, train_y, epochs=30, batch_size=1, verbose=2)
3.7 模型预测
def model_predict(model, trainX, testX, scaler): '''输入训练数据和测试数据,模型输出预测结果。 args: model: lstm模型 trainX: 训练数据的特征 testX: 测试数据的特征 scaler: 做缩放的对象,用于将归一化的数据还原 returns: 二元组,(train_predict, test_predict) train_predict: 训练数据的预测结果 test_predict: 测试数据的预测结果 ''' train_predict = model.predict(trainX) test_predict = model.predict(testX) # 归一化数据还原 train_predict = scaler.inverse_transform(train_predict) test_predict = scaler.inverse_transform(test_predict) return train_predict, test_predict
3.8 训练模型并查看结果
look_back = 10 # 设置往回看的步长为10 trainX, trainY = create_dataset(train, look_back) testX, testY = create_dataset(test, look_back) trainX = np.reshape(trainX, (trainX.shape[0], 1, trainX.shape[1])) testX = np.reshape(testX, (testX.shape[0], 1, testX.shape[1])) model = create_lstm_model(look_back) model_fit(model, trainX, trainY) train_predict, test_predict = model_predict(model, trainX, testX, scaler)



3.9 预测未来5次成绩
# 预测未来五次成绩 predict_scores = [] times = 5 datas = dataset[-look_back:].flatten() while times: datas = datas[-look_back:] input_datas = datas.reshape(1, 1, -1) print(input_datas) predict_score = model.predict(input_datas).flatten() print(predict_score) predict_scores.append(predict_score) datas = np.append(datas, predict_score) times -= 1 predict_scores = scaler.inverse_transform(predict_scores) print(predict_scores) plt.plot(predict_scores)

predict_datas = np.empty_like(dataset) predict_datas[:, :] = np.nan real_datas = scaler.inverse_transform(dataset) predict_datas[-1] = real_datas[-1] predict_datas = np.append(predict_datas, predict_scores, axis=0) plt.plot(real_datas, label='real') plt.plot(predict_datas, label='predict') plt.legend()

4、实验总结
本文通过自己构造的数据,完成数据预处理及时序模型的训练预测,帮助理解python数据科学的一般过程。另外,在构造数据中熟悉了numpy的使用; 在读取数据及做数据分析及异常值处理时熟悉了pandas的使用; 通过matplotlib绘制图达到直观展示数据的效果;做时序预测时熟悉了keras的使用。基本达到了熟悉python相关科学计算库使用的目的。
有兴趣的同学可以照着代码做实验,实验环境最好是python3.x或是python2.7,直接安装使用anaconda最为便捷。
希望对你有用,谢谢。