How to process sensor data

對sensor數據的預處理

import pandas as pd
import numpy as np

import matplotlib.pyplot as plt
from scipy import stats
from sklearn import metrics

import tensorflow as tf
from tensorflow.keras import models
from tensorflow.keras import layers

1. 讀取csv文件得到dataFrame

如果沒有head需要加上列的名字

columns = ['user','activity','timestamp', 'x-axis', 'y-axis', 'z-axis']
def read_data(file_patch):
  train = pd.read_csv(file_patch, header = None, names = columns)
  train = train.dropna()
  return train

2. 對數據進行歸一化處理

# mean and std
def feature_normalize(feature):
  mu = np.mean(feature, axis=0)
  sigma = np.std(feature, axis=0)
  return (feature - mu) / sigma

3. 形成訓練測試數據集

# x1,y1,z1, x2, y2, z2

//窗口大小time_steps; 數據是疊加的每次移動的大小step
def create_segments_for_rnn(df, step, time_steps=200):
  X_train = []
  Y_train = []
  hot_test = []
  for i in range(0, df.shape[0] - time_steps, step):

    //獲得幾列數據中的從第幾行到第幾行,得到仍是dataframe,轉換爲narray
    xyz_data = df[['x-axis', 'y-axis', 'z-axis']][i:i+time_steps]
    X_train.append(np.array(xyz_data))

    //給數據加標籤

    label = stats.mode(df['activity'][i: i + time_steps])[0][0]
    hot_test.append(label)
  #怎樣找到 one-hot和字符串的對應關係?

   get_dummies對後面的字符串列表進行one-hot編碼,編碼的結果之和字符串的字母順序相關和字符串的排列順序無關,總是按字母序排列 如:list('abcf') 還是list('fbac')得到的a的編碼總是[1.0, 0, 0, 0] bcf也是這樣

每次到這裏,都會花費好長時間:pd.Series(list('abcf')是

one-hot 編碼的數據源:會表示成dataframe的Index: 如下面的list('abcf'): ['a', 'b', 'c', 'f'] 注意不是上面的列: a/b/c/f

one-hot編碼需要的幾位:表示爲column

 ['a', 'b', 'c', 'f'] 對應的One-hot向量是:index[0,1,2,3] 對應的向量, 如下圖所示

In [69]: pd.get_dummies(pd.Series(list('abcf')), dtype=float)
Out[69]: 
     a    b    c    f
0  1.0  0.0  0.0  0.0
1  0.0  1.0  0.0  0.0
2  0.0  0.0  1.0  0.0
3  0.0  0.0  0.0  1.0

In [70]: pd.get_dummies(pd.Series(list('fbac')), dtype=float)
Out[70]: 
     a    b    c    f
0  0.0  0.0  0.0  1.0
1  0.0  1.0  0.0  0.0
2  1.0  0.0  0.0  0.0
3  0.0  0.0  1.0  0.0

所以找到字符串和one-hot對應關係的方法也很簡單:

得到所有的字符串列表,df['activity'].df['activity'].value_counts(),然後pd.get_dummies(hot_test)就能找到對應的關係

  Y_train = np.asarray(pd.get_dummies(hot_test), dtype = np.float32)
  return np.array(X_train), Y_train

3.1 scipy.stats.mode函數,尋找出現次數最多的成員

Python中的scipy.stats.mode函數,尋找出現次數最多的成員
from scipy.stats import mode
list = ['a', 'a', 'a', 'b', 'b', 'b', 'a']
print("# Print mode(list):", mode(list))
print("# list中最常見的成員爲:{},出現了{}次。".format(mode(list)[0][0], mode(list)[1][0]))
 
# Print mode(list): ModeResult(mode=array(['a'], dtype='<U1'), count=array([4]))
# list中最常見的成員爲:a,出現了4次。

3.2 one -hot編碼

請注意one-hot的編碼是行向量的的形式不是列的形式

In [77]: LABELS = ['Downstairs', 'Jogging', 'Walk', 'Sitting', 'Standing', 'Upstairs', 'Walk']

In [78]: pd.get_dummies(LABELS)
Out[78]: 
   Downstairs  Jogging  Sitting  Standing  Upstairs  Walk
0           1        0        0         0         0     0
1           0        1        0         0         0     0
2           0        0        0         0         0     1
3           0        0        1         0         0     0
4           0        0        0         1         0     0
5           0        0        0         0         1     0
6           0        0        0         0         0     1
 

shuffle data: 打亂訓練數據順序

def shuffle_data(X, Y): //索引取隨機數
  np.random.seed(10)
  randomList = np.arange(X.shape[0])
  np.random.shuffle(randomList)
  return X[randomList], Y[randomList]

訓練數據和驗證數據分割

def split_data(X,Y,rate):
  X_train = X[int(X.shape[0]*rate):]
  Y_train = Y[int(Y.shape[0]*rate):]
  X_val = X[:int(X.shape[0]*rate)]
  Y_val = Y[:int(Y.shape[0]*rate)]
  return X_train, Y_train, X_val, Y_val

模型的構建

sensor的序列數據可以看成1通道的圖像數據只是 x 不等於 y, input shape可描述爲 (128, 3, 1), 這樣就可以用圖像處理用的Conv2D、DepthwiseConv2D,只是kernel的形狀不是對稱的。

有關DepthwiseConv2D和Conv2D的區別:DepthWiseConv2D是MobileNet提出的是爲了減小模型的大小,但對1 channel而言兩者大概是一致的。

當前的理解是Depth的depth_multiplier類似於Conv的 feature number

depthwise conv2D

model_dipth = models.Sequential()
model_dipth.add(layers.DepthwiseConv2D((4, 3), activation='relu', padding='same', depth_multiplier=8, input_shape=(128, 3, 1)))
model_dipth.add(layers.MaxPooling2D((3, 3)))
model_dipth.add(layers.Conv2D(16, (4, 1), padding='same', activation='relu'))
model_dipth.add(layers.MaxPooling2D((3, 1)))
model_dipth.add(layers.Flatten())
model_dipth.add(layers.Dense(16, activation='relu'))
model_dipth.add(layers.Dense(6, activation='softmax'))
model_dipth.compile(optimizer='adam',
              loss='categorical_crossentropy',
              metrics=['accuracy'])
model_dipth.summary()

conv2D


model_dipth = models.Sequential()
model_dipth.add(layers.Conv2D(16, (4, 3), activation='relu', padding='same', input_shape=(128, 3, 1)))
model_dipth.add(layers.MaxPooling2D((3, 3)))
model_dipth.add(layers.Conv2D(32, (4, 1), padding='same', activation='relu'))
model_dipth.add(layers.MaxPooling2D((3, 1)))
model_dipth.add(layers.Flatten())
model_dipth.add(layers.Dropout(0.5))
model_dipth.add(layers.Dense(16, activation='relu'))
model_dipth.add(layers.Dense(6, activation='softmax'))

1DCNN

  model = Sequential()
  model.add(Conv1D(30, 10, activation='relu', input_shape=(shape[1], shape[2])))
  #model.add(Conv1D(30, 10, activation='relu'))
  model.add(MaxPooling1D(3))
  #model.add(Conv1D(48, 10, activation='relu'))
  model.add(Conv1D(48, 10, activation='relu'))
  #model.add(GlobalAveragePooling1D())
  model.add(Flatten())
  model.add(Dropout(0.5))
  model.add(Dense(num_classes, activation='softmax'))
  print(model.summary())

  • filters: 整數,輸出空間的維度 (即卷積中濾波器的輸出數量)。
  • kernel_size: 一個整數,或者單個整數表示的元組或列表, 指明 1D 卷積窗口的長度。
  • strides: 一個整數,或者單個整數表示的元組或列表, 指明卷積的步長

從實際的結果看還是1DCnn的效果最好且如果卷積後直接flatten而不進行maxpool效果是穩定的(放着手機不動推斷的結果不變),其他推斷的結果是來回變化的,具體原因是訓練的數據集的問題還是模型的問題?後面還要仔細分析

 

損失函數的選擇

categorical_crossentropy VS. sparse_categorical_crossentropy

原以爲損失函數隨便選個就行,看tensorflow給的一個例子是sparse_categorical_crossentropy, 也使用sparse_categorical_crossentropy,在fit時出現如下錯誤:

InvalidArgumentError:  Incompatible shapes: [32,6] vs. [32]
     [[node metrics_6/accuracy/Equal (defined at <ipython-input-80-987e0310275c>:1) ]] [Op:__inference_keras_scratch_graph_4523]
使用PyCharm也沒debug到原因,後來想到原來沒有問題的 loss function, 發現使用categorical_crossentropy沒有問題

https://jovianlin.io/cat-crossentropy-vs-sparse-cat-crossentropy/

給的解釋是

  • If your targets are one-hot encoded, use categorical_crossentropy.
  • But if your targets are integers, use sparse_categorical_crossentropy.
    • Examples of integer encodings (for the sake of completion):
      • 1
      • 2
      • 3

怎樣保存得到訓練、驗證數據不是每次都生成

每次生成訓練的數據時間很長,而要多次進行模型的選擇和訓練?把得到數據寫到文件,下次直接從文件讀出,大大節省了時間,有空仔細研究下Memory

from joblib import Memory
mem=Memory(".cache")
# x1,y1,z1, x2, y2, z2
@mem.cache()
def create_segments_for_rnn(df, step, time_steps=200):
  X_train = []
  Y_train = []
  hot_test = []
  for i in range(0, df.shape[0] - time_steps, step):
    xyz_data = df[['x-axis', 'y-axis', 'z-axis']][i:i+time_steps]
    X_train.append(np.array(xyz_data))

    label = stats.mode(df['activity'][i: i + time_steps])[0][0]
    hot_test.append(label)
  #怎樣找到 one-hot和字符串的對應關係?
  Y_train = np.asarray(pd.get_dummies(hot_test), dtype = np.float32)
  return np.array(X_train), Y_train

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章