Python數據科學實踐

本文使用一個完整的例子來理解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-1 第一位同學成績趨勢圖

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-2 第二位同學成績趨勢圖

1.3 構造第3位同學成績

# 第三位同學, 成績較好但波動較大  rand3 = np.random.normal(0, 5, N)  avg3 = 88  std3 = np.rint(avg3 + rand3)
圖1-3 第三位同學成績趨勢圖

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-4 第四位同學成績趨勢圖

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-5 第五位同學成績趨勢圖

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-6 構造的五位同學成績趨勢圖總覽

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-1 使用pandas讀取數據

2.2 查看各個同學成績的概況

# 查看統計信息,可以看到哪個同學波動較大,哪個同學平均分較高等,卻很難像曲線圖那樣直觀看出各個同學的分數趨勢  df.describe()
圖2-2 顯示各個同學成績的統計信息

2.3 剔除臟數據

df.plot(figsize=(10, 5))
圖2-3 存在數據缺失和超分的異常數據
# 將超過100分的數據設置為100分滿分  df[df > 100] = 100  # 處理缺失值, 用缺失值前面的有效值從前往後填補  df = df.fillna(method='ffill', axis=0)  df.plot(figsize=(10, 5))
圖2-4 處理完缺失數據和異常數據後的趨勢圖
# 通過曲線可以直觀看出:  # 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-1 第五位同學的成績具有周期性和上升趨勢

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-2 在訓練集上的預測結果
圖3-3 在測試集上的預測結果
圖3-4 在訓練集和測試集上各種的預測效果

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)
圖3-5 預測未來的五次成績
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()
圖3-6 現有數據與未來預測數據拼接的曲線

4、實驗總結

本文通過自己構造的數據,完成數據預處理及時序模型的訓練預測,幫助理解python數據科學的一般過程。另外,在構造數據中熟悉了numpy的使用; 在讀取數據及做數據分析及異常值處理時熟悉了pandas的使用; 通過matplotlib繪製圖達到直觀展示數據的效果;做時序預測時熟悉了keras的使用。基本達到了熟悉python相關科學計算庫使用的目的。

有興趣的同學可以照着代碼做實驗,實驗環境最好是python3.x或是python2.7,直接安裝使用anaconda最為便捷。

希望對你有用,謝謝。