четвер, 29 серпня 2013 р.

Визначення діяльності людини на основі даних сенсорів смартфона.

Смартфони поєднують в собі величезну кількість функцій, саме тому вони й стали зараз  незмінними компаньйонами людей. Цікавим варіантом є розробка програмного забезпечення, яке дозволяє визначити рухову активність людини на основі даних сенсорів смартфона: сидить, ходить, біжить. Неважко написати програму яка це буде визначати самостійно. Сьогодні я опишу як це зробити з допомогою R.

Для тренування моделі будемо використовувати безкоштовний набір даних з UCI. Тут зібрано дані показів сенсорів смартфона від 30 волонтерів у віці 10-48 років, які носили на зап'ясті Samsung Galaxy S II  і вказували при цьому тип рухової активності. Типи активності такі: стоїть, сидить, лежить, гуляє, піднімається по сходах, спускається по сходах.  Дані сенсорів були попередньо оброблені для відфільтрування шуму. Завантажити набір даних та прочитати детальніший опис можна тут.

Отже, почнемо:

Так як, дане завдання пропонувалось у курсі "Data Analysis", завантажити набір даних можна і таким чином:
# вказуємо url
url = "https://spark-public.s3.amazonaws.com/dataanalysis/samsungData.rda"
# завантажуємо дані в робочу директорію
dataset <- download.file(url, method = "curl", "samsungdata.rda")
# завантажуємо дані в R
samsungData <- data.frame(samsungData)
# конвертуємо у дата фрейм
load("samsungdata.rda")
Два останні стовпці subject - номер волонтера та activity - вид активності. Решта стовпців мають малоінформативні назви типу "fBodyBodyGyroJerkMag.kurtosis..",  перейменуємо їх нескладною функцією:
numbered.var <- function(x) {paste("feature", x, sep="")}; 
cnames.orig <- colnames(samsungData); 
cnames.new <- c(numbered.var(seq(1:561)), c("subject","activity")); 
colnames(samsungData) <- cnames.new

Виберемо набір даних для тренування (trainSD)  та тестування (testSD) моделі:
# trainSD містить спостережння від волонтерів 1, 3, 5, 6
trainSD <- samsungData[samsungData$subject == 1 | samsungData$subject == 3 | samsungData$subject == 5 | samsungData$subject == 6, ]
trainsubj <- trainSD$subject
trainactivity <- trainSD$activity
trainSD <- trainSD[, -c(562, 563)]

# testSD містить спостережння від волонтерів 27, 28, 29, 30
testSD <- samsungData[samsungData$subject >= 27 & samsungData$subject <= 30, ]
testsubj <- testSD$subject
testactivity <- testSD$activity
testSD <- testSD[, -c(562, 563)]

Для побудови моделі використаємо алгоритм  "випадкового лісу". Цей  алгоритм дозволить вибрати лише ті фактори (покази сенсорів), які впливають на визначення активності.
library(randomForest)
rfmod <- randomForest(as.factor(activity) ~., data = trainSD,  
                    importance=TRUE, proximity=TRUE, 
                    ntree = 500, mtry = 40)

Подивимось на точність моделі:
> print(rfmod)

Call:
 randomForest(formula = as.factor(trainactivity) ~ ., data = trainSD,      importance = TRUE, proximity = TRUE, ntree = 500, mtry = 40) 
               Type of random forest: classification
                     Number of trees: 500
No. of variables tried at each split: 40

        OOB estimate of  error rate: 0.76%
Confusion matrix:
         laying sitting standing walk walkdown walkup class.error
laying      221       0        0    0        0      0 0.000000000
sitting       0     195        3    0        0      0 0.015151515
standing      0       2      225    0        0      0 0.008810573
walk          0       0        0  263        3      0 0.011278195
walkdown      0       0        0    0      192      1 0.005181347
walkup        0       0        0    1        0    209 0.004761905

Як бачимо, дана модель пояснює більше 99 % тренувального набору даних.

Погратися з параметрами і обрати найкращу модель випадкового лісу можна використовуючи функцію tuneRF:
tuneRF(trainSD, as.factor(trainactivity), ntreeTry = 500, stepFactor = 2)
tuneRF(trainSD, as.factor(trainactivity), ntreeTry = 500, stepFactor = 1.5)
tuneRF(trainSD, as.factor(trainactivity), ntreeTry = 1000, mtryStart = 18, stepFactor = 4, improve = 0.01)
tuneRF(trainSD, as.factor(trainactivity), ntreeTry = 2500, mtryStart = 30, stepFactor = 4, improve = 0.01)

Функція varImpPlot покаже найважливіші предіктори.
Перевіримо точність моделі на тестовому наборі:
> 
# будуємо прогноз:
predictactivity  <- predict(rfmod, testSD)
# матриця відповідності реальне/прогнозоване значення
> table(predictactivity , t(testactivity))        
prrf       laying sitting standing walk walkdown walkup
  laying      293       0        0    0        0      0
  sitting       0     224       30    0        0      0
  standing      0      40      253    0        0      7
  walk          0       0        0  222        2      0
  walkdown      0       0        0    7      193     16
  walkup        0       0        0    0        5    193

Обчислимо точність прогнозу у відсотках:
> trueRate <- function(x, y){
+   sumi = 0
+   for (i in 1: length(y) ) {
+     if (x[i] == y[i]) sumi = sumi +1
+   }  
+   return(sumi / length(y))
+ }
> 
> trueRate(predictactivity, testactivity)
[1] 0.9279461
Отже, наша модель дозволяє визначити рухову активність з точністю 92,79%. Непогано.
Можна починати писати софт ).

Звичайно, смартфон з собою носити тяжко, але от ідея застосування алгоритмів machine learning  для біореєстратора Basis - дуже класна ідея.

Немає коментарів:

Дописати коментар