# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# # Human Activity Recognition

# + [markdown] colab_type="text" id="7SuEAVMA69am"
# <NAME>  
# <NAME> 
# -

# The aim of this project was labelling different human activities upon the data register by 5 dimensional signals: a 2-axes accelerometer and a 3-axes gyroscope, in semi-naturalistic conditions.
#
# The set of activities recorded for labelling were:
#
# - running
# - walking
# - standing
# - sitting
# - lying
#
# The data provided for this assignment corresponded to 10 different people, 8 of them labelled and having a sample frequeency of 16 Hz, and 2 of them unlabelled. Each of the recordings lasted less than 20 minutes.
#
# The main goal of this project is to infer the activity carried out by the 2 unlabelled sequences.

# ## Load the dataset

# The data available was transferred into two different pandas dataframes, one corresponding to the training data (8 labelled sequences) and which resulted into a matrix of 141426 rows and 6 columns, and another one corresponding to the testing data (2 unlabelled sequences) which resulted into a matrix of 42188 rows and 5 columns. Moreover, the first five columns of both dataframes corresponded to each of the 5 dimensional signals explained before, and the remaining column from the training dataframe which corresponds to the labelled activity that had been developed at that moment. 

# + colab={"base_uri": "https://localhost:8080/", "height": 118} colab_type="code" executionInfo={"elapsed": 30260, "status": "ok", "timestamp": 1589461905037, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="8-sT3AJzkmNu" outputId="c650727a-cba8-4f5c-8525-423a1c0b2583"
# Load the Drive helper and mount
from google.colab import drive

# This will prompt for authorization.
drive.mount('/content/drive')

# Change to assignment directory 
import os
os.chdir('/content/drive/My Drive/Colab Notebooks/Lab_Exercises_DASS/LAB2/')

# + colab={} colab_type="code" id="RyWE4Y0rlAe0"
from scipy.io import loadmat,savemat
import pandas as pd
import numpy as np
import os
import matplotlib.pyplot as plt

# + [markdown] colab_type="text" id="NfPzzesaa2Sq"
# Load data:

# + colab={} colab_type="code" id="8Yc1GX9ktm0T"
data = loadmat('HAR_database.mat')
train_data = data['database_training']
test_data = data['database_test']

# + [markdown] colab_type="text" id="RTvR0Exoa5p0"
# Create a data frame for training data:

# + colab={} colab_type="code" id="JGlECVYW2prO"
d1 = {'acc_z': train_data[0][0][0], 'acc_xy': train_data[0][0][1], 'gyro_x': train_data[0][0][2], 'gyro_y': train_data[0][0][3], 'gyro_z': train_data[0][0][4], 'label': train_data[0][1][0]}
d2 = {'acc_z': train_data[1][0][0], 'acc_xy': train_data[1][0][1], 'gyro_x': train_data[1][0][2], 'gyro_y': train_data[1][0][3], 'gyro_z': train_data[1][0][4], 'label': train_data[1][1][0]}
d3 = {'acc_z': train_data[2][0][0], 'acc_xy': train_data[2][0][1], 'gyro_x': train_data[2][0][2], 'gyro_y': train_data[2][0][3], 'gyro_z': train_data[2][0][4], 'label': train_data[2][1][0]}
d4 = {'acc_z': train_data[3][0][0], 'acc_xy': train_data[3][0][1], 'gyro_x': train_data[3][0][2], 'gyro_y': train_data[3][0][3], 'gyro_z': train_data[3][0][4], 'label': train_data[3][1][0]}
d5 = {'acc_z': train_data[4][0][0], 'acc_xy': train_data[4][0][1], 'gyro_x': train_data[4][0][2], 'gyro_y': train_data[4][0][3], 'gyro_z': train_data[4][0][4], 'label': train_data[4][1][0]}
d6 = {'acc_z': train_data[5][0][0], 'acc_xy': train_data[5][0][1], 'gyro_x': train_data[5][0][2], 'gyro_y': train_data[5][0][3], 'gyro_z': train_data[5][0][4], 'label': train_data[5][1][0]}
d7 = {'acc_z': train_data[6][0][0], 'acc_xy': train_data[6][0][1], 'gyro_x': train_data[6][0][2], 'gyro_y': train_data[6][0][3], 'gyro_z': train_data[6][0][4], 'label': train_data[6][1][0]}
d8 = {'acc_z': train_data[7][0][0], 'acc_xy': train_data[7][0][1], 'gyro_x': train_data[7][0][2], 'gyro_y': train_data[7][0][3], 'gyro_z': train_data[7][0][4], 'label': train_data[7][1][0]}

df1 = pd.DataFrame(d1)
df2 = pd.DataFrame(d2)
df3 = pd.DataFrame(d3)
df4 = pd.DataFrame(d4)
df5 = pd.DataFrame(d5)
df6 = pd.DataFrame(d6)
df7 = pd.DataFrame(d7)
df8 = pd.DataFrame(d8)

frames = [df1, df2, df3, df4, df5, df6, df7, df8]

df = pd.concat(frames, keys = [1,2,3,4,5,6,7,8])

# + colab={"base_uri": "https://localhost:8080/", "height": 391} colab_type="code" executionInfo={"elapsed": 5723, "status": "ok", "timestamp": 1589461918010, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="Jj7X5pu7A9aV" outputId="cad1acb5-a4e1-4dc6-ae91-da4e6d39225a"
df


# + [markdown] colab_type="text" id="EntJF3ZybCjY"
# Create a data frame for tessting data:

# + colab={} colab_type="code" id="a_YB3Rk9mBXM"
d1 = {'acc_z': test_data[0][0][0], 'acc_xy': test_data[0][0][1], 'gyro_x': test_data[0][0][2], 'gyro_y': test_data[0][0][3], 'gyro_z': test_data[0][0][4]}
d2 = {'acc_z': test_data[1][0][0], 'acc_xy': test_data[1][0][1], 'gyro_x': test_data[1][0][2], 'gyro_y': test_data[1][0][3], 'gyro_z': test_data[1][0][4]}

df1 = pd.DataFrame(d1)
df2 = pd.DataFrame(d2)

frames = [df1, df2]

df_test = pd.concat(frames, keys = [1,2])

# + colab={"base_uri": "https://localhost:8080/", "height": 391} colab_type="code" executionInfo={"elapsed": 5673, "status": "ok", "timestamp": 1589461918013, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="bkyMiClbmY1X" outputId="73d385a1-bea8-48e2-b8a1-7c6690cf62c7"
df_test

# + [markdown] colab_type="text" id="nVeVRXtvbHbn"
# ## Obtaining information from data
# -

# The training data provided consists of 8 labelled sequences from 8 different persons who
# developed different activities. There were five different activities: Running (1), Walking (2), Standing(3), Sitting(4) and Lying(5). 
#
# Each of the training sequences had a duration inferior to 20 minutes, while testing sequences are over 20 minutes. Besides, time is not equally distributed among each activity, being standing or
# sitting much more common than running for example.
#
# As the distribution of each activity seems to be similar por each person, it makes sense to take 6 people to train our model and 2 people for evaluate it, so we can have an idea of its accuracy before we apply it to the test set.

# + colab={"base_uri": "https://localhost:8080/", "height": 33} colab_type="code" executionInfo={"elapsed": 5638, "status": "ok", "timestamp": 1589461918014, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="vZmgwlIf99gt" outputId="f4e8a5bb-1456-4c9a-b36e-a32c5a8ed448"
#activities
val = np.sort(df.label.unique())
print(val)

# + colab={"base_uri": "https://localhost:8080/", "height": 33} colab_type="code" executionInfo={"elapsed": 5609, "status": "ok", "timestamp": 1589461918015, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="fGVjYfHd_6CY" outputId="0798eae0-b4bb-47e8-8878-b7fd55053018"
#rows per activity
count = []

for i in val:
    count.append(df.label[df['label']==i].count())

print(count)
# A lot more data for activities 3 and 5

# + colab={"base_uri": "https://localhost:8080/", "height": 147} colab_type="code" executionInfo={"elapsed": 5565, "status": "ok", "timestamp": 1589461918016, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="VHicTmHuSqR4" outputId="e9e1e673-b207-4d1e-8b66-5d75d4a61212"
#rows per activity per person
p_count = []

for i in range(1,9):
  p_count_i = []
  for j in val:
     p_count_i.append((df.loc[i]).label[df.loc[i,'label']==j].count())
  p_count.append(p_count_i)

#print(p_count)
display(p_count)

# + colab={"base_uri": "https://localhost:8080/", "height": 147} colab_type="code" executionInfo={"elapsed": 5537, "status": "ok", "timestamp": 1589461918018, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="7ZxBvSnH5lr1" outputId="5d18eb89-27c6-42b6-8c07-0d6284d8c136"
# Duration (minuts) for each recording (train)
for i in (range(1,9)):
  print((((df.loc[i]).shape[0]))/(60*16))

# + colab={"base_uri": "https://localhost:8080/", "height": 50} colab_type="code" executionInfo={"elapsed": 6844, "status": "ok", "timestamp": 1589461919359, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="82OwEaAcmmgF" outputId="ddd66a54-3a4d-4590-9a0c-72eb859cf0bf"
# Duration (minuts) for each recording (test)
for i in (range(1,3)):
  print((((df_test.loc[i]).shape[0]))/(60*16))

# + colab={"base_uri": "https://localhost:8080/", "height": 33} colab_type="code" executionInfo={"elapsed": 6814, "status": "ok", "timestamp": 1589461919362, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="7_Ayukoi8CHK" outputId="66382748-c7b6-4ee7-9b63-eea4422e403a"
#rows per person (train)
p_size = []
for i in (range(1,9)):
  p_size.append(((df.loc[i]).shape[0]))
print(p_size)

# + colab={"base_uri": "https://localhost:8080/", "height": 33} colab_type="code" executionInfo={"elapsed": 6779, "status": "ok", "timestamp": 1589461919364, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="x7wHhzd3nCeK" outputId="f667a1cb-3691-4075-d5c6-4fe0e704db76"
#rows per person (train and test)
p_size_total = []
for i in (range(1,9)):
  p_size_total.append(((df.loc[i]).shape[0]))
for i in range(1,3):
   p_size_total.append(((df_test.loc[i]).shape[0]))
print(p_size_total)

# + colab={"base_uri": "https://localhost:8080/", "height": 295} colab_type="code" executionInfo={"elapsed": 6751, "status": "ok", "timestamp": 1589461919366, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="o1MbQS2pLiYi" outputId="a9ba9b5a-c07c-4005-db6b-dcac29a926c7"
bars = ('1', '2', '3', '4', '5', '6', '7', '8','1','2')
y_pos = np.arange(len(bars))
 
# Create bars and choose color
#plt.bar(y_pos, p_size,color=('m','y','g','purple','salmon','b','olive','c'))
plt.bar(y_pos, p_size_total,color=('b','b','b','b','b','b','b','b','m','m'))

# Add title and axis names
plt.title('Distribution of the amount of data for each person (train/test)')
plt.xlabel('Persons')
plt.ylabel('Counts')
 
# Create names
plt.xticks(y_pos, bars)
 
# Show graphic
plt.show()


# + colab={} colab_type="code" id="b360RpLmoium"
def plot_person_activities(count):
  plt.figure()
  bars = ('Running', 'Walking', 'Standing', 'Sitting', 'Lying')
  y_pos = np.arange(len(bars))
  # Create bars and choose color
  plt.bar(y_pos, count ,color=('m','y','g','salmon','b'))
  
  # Add title and axis names
  plt.title('Distribution of the amount of data for each activity')
  plt.xlabel('Activities')
  plt.ylabel('Counts')
  
  # Create names
  plt.xticks(y_pos, bars)
  # Show graphic
  plt.show()



# + colab={"base_uri": "https://localhost:8080/", "height": 295} colab_type="code" executionInfo={"elapsed": 6703, "status": "ok", "timestamp": 1589461919374, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="xsu6n2I6piIK" outputId="26af5339-514e-4092-b6d5-1559989254fb"
plot_person_activities(count)

# + colab={"base_uri": "https://localhost:8080/", "height": 1000} colab_type="code" executionInfo={"elapsed": 7772, "status": "ok", "timestamp": 1589461920474, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="zsxRkA2Spo1C" outputId="387261c9-c316-483f-cfef-53e514501258"
for i in range(8):
  print('Person',i+1)
  plot_person_activities(p_count[i])


# + colab={} colab_type="code" id="519l8xhBMHRv"
#Plot for each variable
def plot_person(person):
    plt.figure()
    c = 1
    # create a plot for each column
    for col in list(person.columns):
      plt.subplot(person.shape[1], 1,c)
      plt.plot(person.loc[:,col])
      c=c+1
    plt.show()


# + colab={"base_uri": "https://localhost:8080/", "height": 1000} colab_type="code" executionInfo={"elapsed": 13556, "status": "ok", "timestamp": 1589461926313, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="cMT26SMOMsnS" outputId="1df702e5-235a-4c10-9a74-1ce0956ad79e"
#Plot for each variable for each person
for i in range(1,9):
  print('Person', i)
  plot_person(df.loc[i])


# + [markdown] colab_type="text" id="RiTqkbAexoIN"
# ## Signal Segmentation
# -

# Learn or predict from a continuous flow of data is a difficult task and can face to some tricky
# issues. A reasonable solution to this would be grouping single observations and working with a bunch
# of instances instead of with single ones. This is what segmentation is based on.
#
# Thus, data had been split into windows. In our case, we have set 16 observations per window, which corresponded to 1 second of the signal, with an overlapping of 50% between them. For testing data, any overlapping had been introduced in order to assign the predicted label to the corresponding instance.
#
# The activity assigned to each window corresponded to the most repeated value, i.e., the mode of the labels of that window data. In the end, a three dimensional array [number of windows, number of instances, number of signal components] had been obtained.

# + colab={} colab_type="code" id="rlRgGBpbxnK1"
def windows(data,size,mode):

    if mode == 'train':
        start = 0
        while start < len(data):
            if(start+size < len(data)):
              yield int(start), int(start + size)
            
            #elif(start+size/2 <= len(data)):
            # yield int(start), int(len(data))
            start += (size / 2)

    if mode =='test':
        start = 0
        while start < len(data):
            if(start+size < len(data)):
              yield int(start), int(start + size)
            
            #elif(start+size/2 <= len(data)):
            # yield int(start), int(len(data))
            start += size


# + colab={} colab_type="code" id="-xOKtwQ60sfX"
window_size = 16

# + colab={} colab_type="code" id="ZqwQcQFH2pD2"
from scipy import stats

#16 rows implies 1 second

def segment_signal(data,window_size = window_size):

    segments = np.empty((0,window_size,5))

    labels = np.empty((0))

    for (start, end) in windows(range(data.shape[0]), window_size,'train'):

        #if(start+window_size<data.shape[0]):
        acc_z = data["acc_z"][start:end]
        acc_xy = data["acc_xy"][start:end]
        gyro_x = data["gyro_x"][start:end]
        gyro_y = data["gyro_y"][start:end]
        gyro_z = data["gyro_z"][start:end]

        segments = np.vstack([segments,np.dstack([acc_z,acc_xy,gyro_x,gyro_y,gyro_z])])
        labels = np.append(labels,stats.mode(data["label"][start:end])[0][0])

    return segments, labels


# + colab={} colab_type="code" id="DdBGlTW4q5iE"
def segment_signal_test(data,window_size = window_size):

    segments = np.empty((0,window_size,5))

    for (start, end) in windows(range(data.shape[0]), window_size,'test'):

        acc_z = data["acc_z"][start:end]
        acc_xy = data["acc_xy"][start:end]
        gyro_x = data["gyro_x"][start:end]
        gyro_y = data["gyro_y"][start:end]
        gyro_z = data["gyro_z"][start:end]

        segments = np.vstack([segments,np.dstack([acc_z,acc_xy,gyro_x,gyro_y,gyro_z])])

    return segments


# + colab={} colab_type="code" id="tL0h9B4kbdii"
# Changing categories from 1 - 5 to  0 - 4

df["label"] = df["label"] - 1

# + colab={} colab_type="code" id="d0gFWKtj2G7t"
data, labels = segment_signal(df)

# + colab={} colab_type="code" id="-0iFTfLcROcd"
test_data1 = segment_signal_test(df_test.loc[1])
test_data2 = segment_signal_test(df_test.loc[2])

# + colab={"base_uri": "https://localhost:8080/", "height": 50} colab_type="code" executionInfo={"elapsed": 56238, "status": "ok", "timestamp": 1589461969169, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="uHfrinhxZTKF" outputId="2c3df154-7f4e-48da-cbed-c3e1b02a7dac"
print(test_data1.shape)
print(test_data2.shape)

# + [markdown] colab_type="text" id="xf0p7jMTcL--"
# ## Feature extraction
#
#
# -

# The purpose of this step was to catch the main characteristics of each segment so our classification algorithm was able to learn from representative and reliable attributes. From each window, the following features had been extracted from each original components to obtain explanatory information of the data: mean, root mean squared value, standard deviation, kurtosis, skewness and correlation between each signal component. This way, the new feature tensor obtained was a 3-dimensional array with dimensions [number of windows, number of extracted features, number of signal components].

# + colab={} colab_type="code" id="cL_8gUpeob4w"
import math

#root mean squared value
def rms(arr):
  square = 0
  for i in range(len(arr)):
    square += (arr[i])**2
  return (math.sqrt(square/len(arr)))
48
def extract_rmsv(data):
  rmsv = []
  for i in range(data.shape[0]):
    acc_z = []
    acc_xy = []
    gyro_x = []
    gyro_y = []
    gyro_z = []
    for j in range(data.shape[1]):
      acc_z.append(data[i][j][0])
      acc_xy.append(data[i][j][1])
      gyro_x.append(data[i][j][2])
      gyro_y.append(data[i][j][3])
      gyro_z.append(data[i][j][4])
    
    rmsv_wind = [rms(acc_z),rms(acc_xy),rms(gyro_x),rms(gyro_y),rms(gyro_z)]
    rmsv.append(rmsv_wind)
  rmsv = np.array(rmsv)
  return(rmsv)


# + colab={} colab_type="code" id="DKdPGizKtaoY"
def extract_features(data):

    mean = np.mean(data,axis=1).reshape(data.shape[0],1,5)

    std = np.std(data,axis=1).reshape(data.shape[0],1,5)

    kts = stats.kurtosis(data,axis=1).reshape(data.shape[0],1,5)

    sk = stats.skew(data,axis=1).reshape(data.shape[0],1,5)

    rmsv = extract_rmsv(data).reshape(data.shape[0],1,5)

    # Bucle para sacar el array de dimensiones (n_ventanas,n_correlaciones=4,n_variables=5).

    # Eliminaremos los elementos de la diagonal de la matriz de correlación puesto que son 1 por definición.

    for i in range(data.shape[0]):

        df = pd.DataFrame(data=data[i])
        corr_df = df.corr(method='pearson')
        corr_np = corr_df.to_numpy()
        cols = []

        for j in range(5):

            cols.append(corr_np[ :,j])
        
        # Eliminamos los elementos de la diagonal.

        cols[0] = np.delete(cols[0],0).reshape(4,1)
        cols[1] = np.delete(cols[1],1).reshape(4,1)
        cols[2] = np.delete(cols[2],2).reshape(4,1)
        cols[3] = np.delete(cols[3],3).reshape(4,1)
        cols[4] = np.delete(cols[4],4).reshape(4,1)

        # Obtenemos la matriz de correlación sin los elementos de la diagonal.

        corr_window = np.hstack((cols[0],cols[1],cols[2],cols[3],cols[4]))

        if i ==0:

            corr = corr_window.reshape(1,4,5)

        else:

            corr_window = corr_window.reshape(1,4,5)

            # Apilamos las matrices de correlación para cada ventana en una nueva dimensión.

            corr = np.vstack((corr,corr_window))
        
    # Obtenemos la matriz de features, de dimensión (n_ventanas,n_features,n_variables) apilando media, std, skewness, kurtosis y correlación en la primera dimensión (de las ventanas).
 
    features = np.concatenate((mean,rmsv,std,kts,sk,corr),axis=1)

    return features


# + colab={} colab_type="code" id="lufWcJxso9DQ"
data = extract_features(data)

n = int(data.shape[0]*0.75) #split index

test_data1 = extract_features(test_data1)

test_data2 = extract_features(test_data2)

# + colab={"base_uri": "https://localhost:8080/", "height": 66} colab_type="code" executionInfo={"elapsed": 78373, "status": "ok", "timestamp": 1589461991403, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="FeU3kPbWZppE" outputId="e99324eb-4813-4446-d8a5-060c00a47780"
print(data.shape)
print(test_data1.shape)
print(test_data2.shape)

# + [markdown] colab_type="text" id="u2OmRkpB_7Ds"
# ## CNN model
# -

# The final part of the project is the classification or recognition stage. In particular, the
# classification algorithm we have implemented is a CNN, for which we used Pytorch. Specifically, the neural network is composed by a convolutional layer, a maxpool stage and three dense layers, each one followed by a non-linear activation function. The network took as inputs the windows grouped in batches. Batch size has been set to 32. Regarding convolutional layer, it was fixed to receive an input with 1 channel, using a convolving kernel of size (2,2) and giving as output an 8 channel array. Then, maxpooling carried out a max over on each (2,2) square. Following, three dense layers separated by non-linear functions performed linear operations. First, two activation functions were rectified functions and the last one was a logsoftmax, which received a final 5 dimensional array for each window and computed the probabilities for each window to belong to each class. This way, we started with a [batch_size, 1, n_features, n_components] array and we get a [batch_size, nlabels] matrix. The model was trained with data corresponding to 6 people and validated with the remaining
# two. Also, during this training stage, an analysis of the cross validation loss during the epochs
# was accomplished in order to control overfitting and got the optimal number of training epochs. 

# + colab={} colab_type="code" id="VZMmh3I8_8qb"
import torch
from torch import nn
from torch import optim

# + colab={} colab_type="code" id="OV8Py1nk51b2"
data = torch.from_numpy(data).float()
labels = torch.from_numpy(labels).float()
test_data1 = torch.from_numpy(test_data1).float()
test_data2 = torch.from_numpy(test_data2).float()

# + colab={} colab_type="code" id="HM3eKDdq7lFy"
train_data = data[0:n]
train_labels = labels[0:n]

valid_data = data[n:]
valid_labels = labels[n:]

# + colab={"base_uri": "https://localhost:8080/", "height": 33} colab_type="code" executionInfo={"elapsed": 81312, "status": "ok", "timestamp": 1589461994414, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="Ou0ImGrsj_2C" outputId="d2849ebe-525d-49af-a940-bc8b90a8bbd8"
test_data1.shape


# + colab={} colab_type="code" id="UKNSI65EQN_s"
def batch(data,targets,size):

    start = 0

    while start < len(data):

        if(start+size < len(data)):

          yield data[start:(start+size)], targets[start:(start+size)]

        start += size


# + colab={} colab_type="code" id="8rDaK-cpkqb0"
def batch_test(data,size):

    start = 0

    while start < len(data):

        if(start+size <= len(data)):

          yield data[start:(start+size)]
        
        #else:

          #yield data[start: ]

        start += size


# + colab={} colab_type="code" id="p0Reu24-QOHW"
class cnn(nn.Module):
    def __init__(self,nlabels=5):
        super().__init__()

        self.nlabels = nlabels

        # convolutional layer
        self.conv = nn.Conv2d(in_channels=1, out_channels=8, 
                               kernel_size=2, stride=1, padding=0)
        
        # Max pool layer
        self.pool = nn.MaxPool2d(2,2)

        # Spatial dimension of the Tensor at the output of the 2nd CNN
        self.final_dim1 = int((9-1)/2)

        self.final_dim2 = int((5-1)/2)
        
        # Linear layers
        
        self.output1 = nn.Linear(8*self.final_dim1*self.final_dim2,32)

        self.output2 = nn.Linear(32,12)

        self.output3 = nn.Linear(12,self.nlabels)
    
        self.relu = nn.ReLU()
        
        self.logsoftmax = nn.LogSoftmax(dim=1) 
        

        
    def forward(self, x):

        x = self.conv(x) 
        x = self.relu(x) 

        x = self.pool(x)

        # Flatten the tensor into a vector
        x = x.view(-1, 8 * self.final_dim1 * self.final_dim2)
        # Pass the tensor through the Dense Layers
        

        x = self.output1(x)
        x = self.relu(x)

        x = self.output2(x)
        x = self.relu(x)
        
        x = self.output3(x)
        x = self.logsoftmax(x)
        
        return x


# + colab={} colab_type="code" id="ORRbVgceQOJ9"
class cnn_extended(cnn):
    
    def __init__(self,nlabels=5,epochs=200,lr=0.001,batch_size=32):
        
        super().__init__(nlabels)

        self.epochs = epochs

        self.lr = lr

        self.batch_size = batch_size

        self.optim = optim.Adam(self.parameters(), self.lr)

        self.criterion = nn.NLLLoss()

        self.loss_during_training = []

        self.valid_loss_during_training =[]
        
    def trainloop(self,train_data,train_labels,valid_data,valid_labels):
        
        for e in range(int(self.epochs)):

            running_loss = 0.

            counter = 0

            for data,targets in batch(train_data,train_labels,self.batch_size):

                self.optim.zero_grad()

                data = data.view(self.batch_size,1,9,5)

                out = self.forward(data)

                loss = self.criterion(out,targets.long())

                running_loss += loss.item()

                loss.backward()

                self.optim.step()

                counter += 1

            self.loss_during_training.append(running_loss/counter)

            with torch.no_grad():

                running_loss = 0.

                counter = 0

                for data, targets in batch(valid_data,valid_labels,self.batch_size):

                    data = data.view(self.batch_size,1,9,5)

                    out = self.forward(data)

                    loss = self.criterion(out,targets.long())

                    running_loss += loss.item()

                    counter += 1

                self.valid_loss_during_training.append(running_loss/counter)

                print("Epoch %d. Training loss: %f, Validation loss: %f" 
                      %(e,self.loss_during_training[-1],self.valid_loss_during_training[-1]))
                
    def final_trainloop(self,train_data,train_labels):
        
        for e in range(int(self.epochs)):

            running_loss = 0.

            counter = 0

            for data,targets in batch(train_data,train_labels,self.batch_size):

                self.optim.zero_grad()

                data = data.view(self.batch_size,1,9,5)

                out = self.forward(data)

                loss = self.criterion(out,targets.long())

                running_loss += loss.item()

                loss.backward()

                self.optim.step()

                counter += 1

            self.loss_during_training.append(running_loss/counter)

            print("Epoch %d. Training loss: %f" 
                      %(e,self.loss_during_training[-1]))

    def eval_performance(self,dataset,labels):
        
        loss = 0

        accuracy = 0

        counter = 0

        with torch.no_grad():
        
            for data, targets in batch(dataset,labels,self.batch_size):

                data = data.view(self.batch_size,1,9,5)

                probs = self.forward(data)

                top_p, top_class = probs.topk(1,dim=1)

                equals = (top_class == targets.view(data.shape[0],1))

                accuracy += torch.mean(equals.type(torch.FloatTensor))

                counter += 1

            return accuracy/counter

    def predict(self,dataset):

        counter = 0

        with torch.no_grad():
        
            for data in batch_test(dataset,1):

                data = data.view(data.shape[0],1,9,5)

                probs = self.forward(data)

                top_p, top_class = probs.topk(1,dim=1)

                # top_class = torch.squeeze(top_class)

                if counter == 0:

                    predictions = top_class
                
                else:

                    predictions = torch.cat((predictions,top_class),0)

                counter += 1

            return predictions
    


# + colab={"base_uri": "https://localhost:8080/", "height": 1000} colab_type="code" executionInfo={"elapsed": 255736, "status": "ok", "timestamp": 1589462168962, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="-kEd4N_oQOMt" outputId="055427d5-2617-44c8-e934-3dd99bf5cea6"
my_CNN = cnn_extended()

my_CNN.trainloop(train_data,train_labels,valid_data,valid_labels)

# + colab={"base_uri": "https://localhost:8080/", "height": 50} colab_type="code" executionInfo={"elapsed": 255701, "status": "ok", "timestamp": 1589462168967, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="nBHXAUZ9S9Tr" outputId="23847e65-a662-4265-aac6-f18c822f7202"
train_performance = my_CNN.eval_performance(train_data,train_labels)

valid_performance = my_CNN.eval_performance(valid_data,valid_labels)

print("Train accuracy %f" %(train_performance))
print("Validation accuracy %f" %(valid_performance))

# + colab={"base_uri": "https://localhost:8080/", "height": 295} colab_type="code" executionInfo={"elapsed": 256432, "status": "ok", "timestamp": 1589462169711, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="wpXgAOexUZ1q" outputId="37feb58a-0136-4b42-b74f-3e9c231d0b56"
plt.plot(my_CNN.loss_during_training,'-b',label='Training Cross Entropy Loss')
plt.plot(my_CNN.valid_loss_during_training,'-g',label='Validation Cross Entropy Loss')
plt.xlabel('Iterations')
plt.ylabel('Loss')
plt.legend()
# -

# As we see, first epochs rapidly make the cross entropy losses decrease. Around 30 epochs, they are almost stabilized, but some small decreases and increases are shown. The key point here is that from 80 epochs, validation loss slowly increases again, while training loss keeps decreasing. This phenomenon is called overfitting: at that point, the neural network stops learning and starts memorizing the training instances, which affects its generalization ability, and the accuracy on the validation test gets worse. Therefore, network is trained again with the number of epochs that minimizes validations loss and considering the joint of training and validation sets, avoiding the overfitting part (early stopping).
#
# Thus, 98.65% and 96.73% accuracies have been obtained for training and validation set respectively in the first case. On the other hand, the model with the optimal number of epochs yields a 95.1% of success rate on the train data and a 98.8% on the validation instances. It’s clear that the second case is a superior model and is the one we will use in the remaining tasks.
#
# Talking about the obtained success rates,the quality of the results is very high and predictions are extremely accurate. It seems that a convolutional neural network is a right approach to this problem. Thus, a satisfactory human recognition system had been developed. However, we must mention that we were not predicting the activity of each observation itself, but the mode of the activities of 16 observations. Therefore, accuracy would be lower due to the observations in the window that do not have the mode as label. Nevertheless, when analysing the data, we saw that the same activity is performed along a large number of observations, which make sense since normally, a person performs the same activity for at least several seconds. Consequently, a small number of observations are misclassified due to this reason.

# + colab={"base_uri": "https://localhost:8080/", "height": 33} colab_type="code" executionInfo={"elapsed": 256425, "status": "ok", "timestamp": 1589462169716, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="qVhT2UHrk2Db" outputId="822a7aae-14ca-42cc-efa2-da34e529c1e5"
optim_epochs = my_CNN.valid_loss_during_training.index(min(my_CNN.valid_loss_during_training)) + 1

optim_epochs

# + [markdown] colab_type="text" id="qoEPpSmSc5I3"
# Early stopping at  epochs. After that, it starts overfitting.
#

# + colab={"base_uri": "https://localhost:8080/", "height": 1000} colab_type="code" executionInfo={"elapsed": 81554, "status": "ok", "timestamp": 1589462260039, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="bG7-J6iaUZ3n" outputId="15527005-1d70-4110-db88-cb1285568c7b"
my_CNN = cnn_extended(epochs=optim_epochs)

my_CNN.final_trainloop(data,labels)

# + colab={"base_uri": "https://localhost:8080/", "height": 50} colab_type="code" executionInfo={"elapsed": 1361, "status": "ok", "timestamp": 1589462261424, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="K268ai4NUZ7s" outputId="563d7955-ec46-43e9-b75f-163ba56431f5"
train_performance = my_CNN.eval_performance(train_data,train_labels)

valid_performance = my_CNN.eval_performance(valid_data,valid_labels)

print("Train accuracy %f" %(train_performance))
print("Validation accuracy %f" %(valid_performance))

# + colab={"base_uri": "https://localhost:8080/", "height": 50} colab_type="code" executionInfo={"elapsed": 2340, "status": "ok", "timestamp": 1589462262419, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="WdpOTjX3UZ9t" outputId="bf1c2629-0ad9-4f69-933a-02b01e84954e"
predictions1 = my_CNN.predict(test_data1)
predictions1 = torch.squeeze(predictions1)
print(predictions1.shape)

predictions2 = my_CNN.predict(test_data2)
predictions2 = torch.squeeze(predictions2)
print(predictions2.shape)

# + colab={"base_uri": "https://localhost:8080/", "height": 50} colab_type="code" executionInfo={"elapsed": 2328, "status": "ok", "timestamp": 1589462262421, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="sv86ozw2u4V-" outputId="3394e950-368e-4a2a-dc10-7fe023ad39f6"
print(np.unique(predictions1))
print(np.unique(predictions2))


# + [markdown] colab_type="text" id="0NWalxDXvU-x"
# Let's remember that every label in predictions makes references to each window. This means that every target describes 48 observations, so we have to repeat every component 48 times to get a category per observation in the test set. Moreover, a few test observations have been lost in the windowing, but we can attach these few ones to the last label without any significant mistake. The following code do this for both test people.

# + colab={} colab_type="code" id="df-xpyFeKIlK"
def get_final_pred(predictions,fin,ref,window_size = window_size):

    final_predictions = np.empty(ref,dtype=int)

    for i in range(fin):

        final_predictions[window_size*i:window_size*(i+1)] = predictions[i]

    final_predictions[window_size*(i+1): ] = predictions[-1]

    return final_predictions


# + colab={} colab_type="code" id="eA6_7L8FKGs3"

final_predictions_1 = get_final_pred(predictions1,predictions1.shape[0],df_test.loc[1].shape[0])
final_predictions_2 = get_final_pred(predictions2,predictions2.shape[0],df_test.loc[2].shape[0])

# + colab={} colab_type="code" id="Fj3yzM57sjQB"
#Original categories were from 1 to 5
final_predictions_1 = final_predictions_1+1
final_predictions_2 = final_predictions_2+1

# + colab={"base_uri": "https://localhost:8080/", "height": 266} colab_type="code" executionInfo={"elapsed": 1582, "status": "ok", "timestamp": 1589466728356, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="aHHmNjDFkZ7A" outputId="cc478b18-e1bd-4cb2-d7b4-7a05099a2438"
df_test1=df_test.loc[1]
df_test1['label']=final_predictions_1
df_test1
plot_person(df_test1)
# -

# The predicted labels for the first test person showed a similar distribution to the ones from the training set. We observed that all activities were present and that each signal component presented
# peaks of activity as before. On the other hand, the second person presented a different labels
# distribution, where running was not between the predicted activities. Standing was the main activity
# for this person and walking, sitting and lying were in a second plane.

# + colab={"base_uri": "https://localhost:8080/", "height": 297} colab_type="code" executionInfo={"elapsed": 2904, "status": "ok", "timestamp": 1589462263059, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="YGXQiPjOZEd1" outputId="89c28eab-fdf4-491a-95ac-1739a17ca7ee"
plt.plot(final_predictions_1)
plt.title("Activity Person 1")

# + colab={"base_uri": "https://localhost:8080/", "height": 33} colab_type="code" executionInfo={"elapsed": 879, "status": "ok", "timestamp": 1589464966826, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="EZ9PtCOGUOg7" outputId="55f3849a-5d9b-408c-cc57-6f79876691a0"
count_t1 = []

for i in val:
    count_t1.append(sum(final_predictions_1==i))

print(count_t1)

# + colab={"base_uri": "https://localhost:8080/", "height": 295} colab_type="code" executionInfo={"elapsed": 982, "status": "ok", "timestamp": 1589464975857, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="LHBAhyr7UoAM" outputId="d1b8755a-aa7e-4cc6-f997-ed913b0fca07"
plot_person_activities(count_t1)

# + colab={"base_uri": "https://localhost:8080/", "height": 265} colab_type="code" executionInfo={"elapsed": 1452, "status": "ok", "timestamp": 1589466777047, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="bZ9HJFo6mgCb" outputId="e101a6bb-306b-4f1b-be0d-8f533707fc3b"
df_test2=df_test.loc[2]
df_test2['label']=final_predictions_2
df_test2
plot_person(df_test2)

# + colab={"base_uri": "https://localhost:8080/", "height": 297} colab_type="code" executionInfo={"elapsed": 963, "status": "ok", "timestamp": 1589464991021, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="vZCTiOQmZqMj" outputId="5fe05f5f-b22e-49f6-d14d-54db5b39fdd6"
plt.plot(final_predictions_2)
plt.title("Activity Person 2")

# + colab={"base_uri": "https://localhost:8080/", "height": 33} colab_type="code" executionInfo={"elapsed": 1032, "status": "ok", "timestamp": 1589465031923, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="dc1qsGaxVLw7" outputId="7c7670fe-aa12-4bb5-8264-e0b0a378e454"
count_t2 = []

for i in val:
    count_t2.append(sum(final_predictions_2==i))

print(count_t2)

# + colab={"base_uri": "https://localhost:8080/", "height": 295} colab_type="code" executionInfo={"elapsed": 971, "status": "ok", "timestamp": 1589465035289, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="hu784PEtVQLL" outputId="440f4d0f-8c3a-4a8d-a647-2eaabd842016"
plot_person_activities(count_t2)

# + colab={} colab_type="code" id="WSxRi4wgRkhb"
final_predictions_1 = final_predictions_1.reshape(1,final_predictions_1.shape[0])
final_predictions_2 = final_predictions_2.reshape(1,final_predictions_2.shape[0])

# + colab={"base_uri": "https://localhost:8080/", "height": 50} colab_type="code" executionInfo={"elapsed": 1049, "status": "ok", "timestamp": 1589465052858, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="nEurwrw1NaJ-" outputId="1e911c74-6483-4900-fc6f-880a9a335d26"
print(df_test.loc[1].shape[0])
print(final_predictions_1.shape)

# + colab={"base_uri": "https://localhost:8080/", "height": 50} colab_type="code" executionInfo={"elapsed": 1011, "status": "ok", "timestamp": 1589465055821, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="EYc71d4TQ6zd" outputId="f26f858c-4af8-4505-f74a-9bf03350fee7"
print(df_test.loc[2].shape[0])
print(final_predictions_2.shape)

# + [markdown] colab_type="text" id="GFow7GlIRHDf"
# Above, we see that we got a prediction for each test observation

# + colab={"base_uri": "https://localhost:8080/", "height": 50} colab_type="code" executionInfo={"elapsed": 1307, "status": "ok", "timestamp": 1589465059356, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "09868762370980769562"}, "user_tz": -120} id="1azYx6yfNrfy" outputId="fe50366f-d5be-4632-e859-3c96ce920d76"
print(np.unique(final_predictions_1))
print(np.unique(final_predictions_2))

# + colab={} colab_type="code" id="QLAqzT3bRKVm"
results = {'labels_test_1': final_predictions_1, 'labels_test_2': final_predictions_2}

# + [markdown] colab_type="text" id="<KEY>"
# Let's generate the mat file

# + colab={} colab_type="code" id="qErNTu5KSXPj"
savemat("results",results)

StarcoderdataJupyterScriptsDedupFiltered