Activity Recognition using Smartphones — Machine Learning application | by Karan Bhanot | Towards Data Science

When I first began to explore machine learning, I read numerous articles and research papers. One of the papers I discovered initially, involved using Machine Learning to classify activities. And even though implementation seemed a far-fetched goal at that time, I was intrigued by the application. Having gained some experience since that day, I believe today I can apply my machine learning knowledge to recognise activities now.
For the dataset, I selected the training.csv and test.csv files from the Kaggle competition. I worked on this project as a Jupyter notebook which is available in my Activity Recognition using Machine Learning repo.
As a side note, now it’s much easier to find datasets online through Google Dataset Search. This is from where I found the dataset for this project.
So, in this article I’ll explain the steps I took in this project and how I used machine learning to classify activities with over 96% accuracy. Fork the repository, open the notebook and let’s start.
There are a number of repositories that we will need in this project.
numpy and pandas: numpy enables us to work with arrays with great efficiency. Pandas is used to read the dataset file and import it as a dataframe, which is similar to a table with rows and columns.matplotlib: matplotlib is a highly customisable package which has the subpackage pyplot that enables us to draw plots, bar charts, pie charts and more. We get options to add legends, axis titles, change thickness of lines etc. The cm package (colormap) allows us to get colors for our charts.sklearn: This machine learning library includes numerous machine learning algorithms already builtin with certain parameters set as default parameters, so they work right out of the box.
numpy and pandas: numpy enables us to work with arrays with great efficiency. Pandas is used to read the dataset file and import it as a dataframe, which is similar to a table with rows and columns.
matplotlib: matplotlib is a highly customisable package which has the subpackage pyplot that enables us to draw plots, bar charts, pie charts and more. We get options to add legends, axis titles, change thickness of lines etc. The cm package (colormap) allows us to get colors for our charts.
sklearn: This machine learning library includes numerous machine learning algorithms already builtin with certain parameters set as default parameters, so they work right out of the box.
If you notice, I’ve added a line %matplotlib inline. This changes the backend for matplotlib to the Jupyter notebook as a result of which, all plots will now show up inline in the Jupyter notebook itself.
In this project, I have used four algorithms namely Support Vector Classifier as SVC, Logistic Regression as LogisticRegression, K Nearest Neighbors Classifier as KNeighborsClassifier, and Random Forest Classifier as RandomForestClassifier. To calculate accuracy, I imported accuracy_score.
First we will use read_csv() method to import the train and test files into the notebook and save it in the variables training_data and testing_data.
We use shape method to find the size of the dataset. It results in the output as (rows, columns). There are 7352 rows and 563 columns in the training dataset and 2947 rows and 563 columns in the testing dataset. We must ensure that the dataset does not have any null values. We use isnull().values.any() to check if any cell is empty. We print the output and see that the output is False meaning there are no null values. So, we can proceed further.
We can use the head(5) method to get a glimpse of the first 5 rows of the training data. We see there are 563 columns with the last column as Activity which will act as our label. In the remaining columns, subject is of no specific use for our machine learning application as we want to explore the activity and not who performed it. We can drop this column and the remaining 561 columns will be our features. Same will be done for the testing data.
By convention, small letter y acts as the set of labels and capital letter X acts as the set of features. Thus, the names are y_train, X_train, y_test and X_test. We will use these variables during machine learning analysis.
One of the key things when working with data is to ensure that all classes are of approximately equal size. This is essential so that the machine learning algorithm is not biased towards any one class.
Let’s understand this with the help of an example. Say, the dataset is of 30 activities with varied share percentage. The dataset has 99% data for Activity 1 and 1% data for the remaining activities. In such a case, machine learning will never learn any pattern about the data. It’ll consider that for 99 out of 100 cases, the activity will be Activity 1. So, it’ll always output Activity 1 without any consideration for the data and will still achieve 99% accuracy. Such a model is incorrect and thus approximately equal share of different data classes must be ensured.
We first get the count of records for each type of activity in the count_of_each_activity variable. value_counts() gives the counts and np.array converts it into an array. The counts are presented in alphabetical order of the name of the activity.
unique() gives us unique values in y_train. We must sort it so that they align with the count values gathered above. The rcParams helps us define certain styles for out chart. We define the figure size using figure.figsize and the font size using font.size.
We now have our data ready for the pie chart. pie() method creates a pie chart. The first argument is the count for each activity, the second argument is the respective activity name denoted by labels and the third argument autopct computes percentages for each activity.
On observing the pie chart above, you can see that the share of each activity is almost equal. The dataset is very well formed and can be used directly.
Next, I observe the type of readings in the datatset. If you look at the column headings, you can see that the columns have either the text Acc to refer to accelerometer reading, Gyro to refer to gyroscope values or none of the two to refer to all others.
I first iterate through column names, to check if they contain ‘Acc’ or ‘Gyro’ or not. Based on the variable values, I plot a bar plot using bar() method of pyplot subpackage. The first argument are the X axis labels, the second argument takes the array of Y axis values and the color argument defines the colors red, blue and green respectively for the three bars. I again defined the figure size and font size for this bar plot.
To get a better perspective on the data, I understood that I had to take a look at the activities. Thus, I decided that I’ll try to explore more about the ‘Standing’ activity.
This is all the information I knew before I began:
The dataset has activity records for 30 individuals and some individual performed the Standing activity.The data collected is recorded at a stretch for each individual, especially for each activity. This means the records of any given activity will actually be in time series.There are many features in each record, but I must not include all in one attempt as it might make the understanding of the data more difficult.
The dataset has activity records for 30 individuals and some individual performed the Standing activity.
The data collected is recorded at a stretch for each individual, especially for each activity. This means the records of any given activity will actually be in time series.
There are many features in each record, but I must not include all in one attempt as it might make the understanding of the data more difficult.
Based on the information I had, I decided that I’d plot a line graph for all individuals who performed the Standing activity over a time period with respect to a feature. I took the feature as the angle between X and mean Gravity, which should stay almost constant except for minor changes due to human error.
I first began by selecting all rows from the dataset that have the ‘Activity’ label as ‘STANDING’ and store it in standing_activity. Here, we must ensure that we reset the index. This is necessary because when we selected the above rows, the removed rows did get removed but the remaining rows’ index did not change and they were no longer in a continuous order.
The data collected is in continuous time series for each individual and was recorded at the same rate. So, I can simply assign time values to each activity starting from 0 each time the subject changes. For each subject, the Standing activity records will start with a time value of 0 and increment by 1 till the previous row’s subject matches the present row’s subject. I store all the time series in a variable time_series and convert it into a dataframe using pandas method DataFrame() and store it in a variable time_series_df. Lastly, I combine the records and the time series variable together in standing_activity_df using pandas concatenate() method. axis = 1 tells the method to combine the two dataframes and append them as columns.
np.zeros() creates a numpy array of zeros with size equal to the number within parentheses. For a dataframe, appending a square bracket at the end of shape helps us get rows or columns if we use 0 or 1 inside the bracket respectively.
Now, as the data is ready to be plot, I use the matplotlib’s cm subpackage to get a list of colors using the rainbow method.
I then iterate over the list of subjects inside the standing_activity_df. I specify size of the graph using rcParams. In the plot method, the first argument is X-axis values which is Time column in our case. The second column is for Y-axis values so I input the angle(X, gravityMean) values. Color is defined in c, subject numbers are set as label and width of the line is set to 4 in linewidth. I then specify the X-axis label, Y-axis label and title for the plot. legend() method displays the legend on the graph.
If we take a closer look at the graph, we can see that each line on an average, transitions between a maximum range of 0.2–0.3 values. This is indeed the expected behaviour as slight variations can be attributed to minor human errors.
Now comes the final step in our process to actually use machine learning algorithms and make classifications.
We create an array of zeros of size 4 to store accuracy for each algorithm. We will use this while creating the bar plot.
accuracy_scores = np.zeros(4)
The process for each one is the same as I will be using the default values of various parameters. Let’s understand it with the help of Support Vector Classifier. First, I write the name of the algorithm as imported SVC(). This is followed by the fit() method which models the algorithm on the data provided. I input the arguments as training data, hence, X_train and y_train.
Next, I use the predict() method to predict the outputs of the test data, X_test and store it in prediction variable. I then use the accuracy_score function to calculate the accuracy, which takes the first argument as true values and second argument as prediction. I multiplied it by 100 to convert into percentage. We do the same steps for each algorithm.
As you can see from the output values above, the Logistic Regression algorithm performed the best with the accuracy of over 96%. We can also visualise the outputs as a bar graph.
In this article, I discussed Activity Recognition, drew visualisations from the dataset and used machine learning algorithms for classifying activities. As per the results, Logistic Regression achieved the highest accuracy.
I hope you like my work. As a future perspective, you can try other algorithms, or choose different values of parameters to improve the accuracy even further. Please feel free to share your thoughts and ideas.