Introduction to the ActivityIndex package in R
Author: Jiawei Bai
Date: 2021-01-07

# Introduction to the `ActivityIndex` package in `R`

#### Jiawei Bai

#### 2021-01-07

The ActivityIndex package contains functions to 1) read raw accelerometry data and 2) compute “Activity Index” (AI) using the raw data. This introduction provides step-by-step instructions on how to read data from `.csv` files and then compute AI.

# Data description

The sample data were collected by accelerometer GT3X+ (ActiGraph, ), downloaded from . The data are available in the ActivityIndex package and their paths can be acquired using command:

    system.file("extdata", "sample_GT3X+.csv.gz", package = "ActivityIndex")
    system.file("extdata", "sample_table.csv.gz", package = "ActivityIndex")

`sample_GT3X+.csv.gz` is the standard output of GT3X+ accelerometer, with a \(10\)-line header containing the basic information of the data collection, followed by \(3\)-column raw acceleration data. `sample_table.csv.gz` contains the same \(3\)-column acceleration data without the \(10\)-line header. The first \(15\) lines of `sample_GT3X+.csv.gz` are shown below:

    ## ------------ Data File Created By ActiGraph GT3X+ ActiLife v6.7.1 Firmware v2.5.0 date format M/d/yyyy at 30 Hz  Filter Normal -----------
    ## Serial Number: NEO1DXXXXXXXX
    ## Start Time 10:54:00
    ## Start Date 6/27/2012
    ## Epoch Period (hh:mm:ss) 00:00:00
    ## Download Time 16:25:52
    ## Download Date 6/28/2012
    ## Current Memory Address: 0
    ## Current Battery Voltage: 4.22     Mode = 12
    ## --------------------------------------------------
    ## 0,0,0
    ## 0,0,0
    ## 0,0,0
    ## 0,0,0
    ## 0,0,0

while the first \(5\) lines of `sample_table.csv.gz` are

    ## 0,0,0
    ## 0,0,0
    ## 0,0,0
    ## 0,0,0
    ## 0,0,0

Users should follow the same format while preparing their own data.

# Read the data

`ReadGT3XPlus` and `ReadTable` functions read the GT3X+ `.csv.gz` file and the \(3\)-column acceleration table, respectively. To read the data, use the following code

    sampleGT3XPlus = ReadGT3XPlus(system.file("extdata",
        "sample_GT3X+.csv.gz", package = "ActivityIndex"))
    sampleTable = ReadTable(system.file("extdata", "sample_table.csv.gz",
        package = "ActivityIndex"))

Now that object `sampleGT3XPlus` has class `GT3XPlus`, which contains the raw data and header information. Function `ReadGT3XPlus` automatically applies time stamps to the acceleration time series using the information from the header. For example, our sample data look like this

    str(sampleGT3XPlus)

    ## List of 8
    ##  $ SN          : chr "NEO1DXXXXXXXX"
    ##  $ StartTime   : chr "10:54:00"
    ##  $ StartDate   : chr "2012-06-27"
    ##  $ Epoch       : chr "00:00:00"
    ##  $ DownloadTime: chr "16:25:52"
    ##  $ DownloadDate: chr "2012-06-28"
    ##  $ Hertz       : num 30
    ##  $ Raw         :Classes 'data.table' and 'data.frame':   1006080 obs. of  5 variables:
    ##   ..$ Date: chr [1:1006080] "2012-06-27" "2012-06-27" "2012-06-27" "2012-06-27" ...
    ##   ..$ Time: chr [1:1006080] "10:54:00" "10:54:00" "10:54:00" "10:54:00" ...
    ##   ..$ X   : num [1:1006080] 0 0 0 0 0 0 0 0 0 0 ...
    ##   ..$ Y   : num [1:1006080] 0 0 0 0 0 0 0 0 0 0 ...
    ##   ..$ Z   : num [1:1006080] 0 0 0 0 0 0 0 0 0 0 ...
    ##   ..- attr(*, ".internal.selfref")=<externalptr>
    ##  - attr(*, "class")= chr "GT3XPlus"

However, `sampleTable` is much simpler, since limited information was given. The first \(6\) lines of it look like this

    head(sampleTable, n = 6)

    ##    Index X Y Z
    ## 1:     1 0 0 0
    ## 2:     2 0 0 0
    ## 3:     3 0 0 0
    ## 4:     4 0 0 0
    ## 5:     5 0 0 0
    ## 6:     6 0 0 0

# Compute AI

AI is a metric to reflect the variability of the raw acceleration signals after removing systematic noise of the signals. Formally, its definition (a one-second AI) is

\[ \text{AI}^{\text{new}}_i(t;H)=\sqrt{\max\left(\frac{1}{3}\left\{\sum_{m=1}^{3}{\frac{\sigma^2_{im}(t;H)-\bar{\sigma}^2_{i}}{\bar{\sigma}^2_{i}}}\right\},0\right)},\label{EQ: AI} \] where \(\sigma^2_{im}(t;H)\) (\(m=1,2,3\)) is axis-\(m\)’s moving variance during the window starting from time \(t\) (of size \(H\)), and \(\bar{\sigma}_i\) is the systematic noise of the signal when the device is placed steady.

Function `computeActivityIndex` is used to compute AI. The syntax of the function is

    computeActivityIndex(x, x_sigma0 = NULL, sigma0 = NULL,
        epoch = 1, hertz)

`x` is the data used to compute AI. It can either be a `GT3XPlus` object, or a \(4\)-column data frame (tri-axial acceleration time series with an index column). Either `x_sigma0` or `sigma0` are used to determine the systematic noise \(\bar{\sigma}_i\). More detailed example will follow to illustrate how to use them. `epoch` is the epoch length (in second) of the AI. For example, the default `epoch=1` yields to \(1\)-second AI, while minute-by-minute AI is given by `epoch=60`. `hertz` specifies the sample rate (in Hertz), which is usually \(10\), \(30\) or \(80\), etc.

We will continue our example of computing AI using our data `sampleGT3XPlus` and `sampleTable`.

## Find \(\bar{\sigma}_i\) on-the-fly

According to the definition of the systematic noise \(\bar{\sigma}_i\), it changes with subject \(i\). Therefore, strictly speaking, we are to compute \(\bar{\sigma}_i\) every time we compute AI for a new subject \(i\). Argument `x_sigma0` can be used to specify a \(4\)-column data frame (one column for indices and three columns for acceleration) which is used to calculate \(\bar{\sigma}_i\). The \(4\)-column data frame should contain the raw accelerometry data collected while the accelerometer is not worn or kept steady. For example, if we say a segment of our sample data (`sampleTable[1004700:1005600,]`) meets such requirement, we could compute AI using the following code

    AI_sampleTable_x = computeActivityIndex(sampleTable,
        x_sigma0 = sampleTable[1004700:1005600, ], epoch = 1,
        hertz = 30)
    AI_sampleGT3XPlus_x = computeActivityIndex(sampleGT3XPlus,
        x_sigma0 = sampleTable[1004700:1005600, ], epoch = 1,
        hertz = 30)

## Find \(\bar{\sigma}_i\) beforehand

Sometimes we do not want to calculate \(\bar{\sigma}_i\) whenever computing AI. For example, if \(10\) accelerometers were used to collect data over \(100\) subjects, there is no reason to calculate \(\bar{\sigma}_i\) for \(100\) times. One \(\bar{\sigma}_i\) is only needed for one accelerometer. Furthermore, if we could verify the \(\bar{\sigma}_i\)’s of the \(10\) accelerometers are close to each others, we could combine them into a single \(\bar{\sigma}=\sum_{i=1}^{10}{\bar{\sigma}_i}/10\). In this case, \(\bar{\sigma}\) will be used for all subjects in that study, which is crucial for fast processing of data collected by large studies.

This can be achieved by using the argument `x_sigma0` to specify a pre-determined \(\bar{\sigma}_i\). Still using the same segment of data (`sampleTable[1004700:1005600,]`) as an example, we calculate a `sample_sigma0` beforehand with code

    sample_sigma0 = Sigma0(sampleTable[1004700:1005600, ],
        hertz = 30)

Then we could use this `sample_sigma0`=\(0.00218\) to compute AI with code

    AI_sampleTable = computeActivityIndex(sampleTable, sigma0 = sample_sigma0,
        epoch = 1, hertz = 30)
    AI_sampleGT3XPlus = computeActivityIndex(sampleGT3XPlus,
        sigma0 = sample_sigma0, epoch = 1, hertz = 30)

# Explore AI

Using either method to compute AI yield to the same result. The output of function `computeActivityIndex` has two columns: `RecordNo` saves the indices and `AI` stores AI. The first \(10\) lines of `AI_sampleGT3XPlus` is as follow

    head(AI_sampleGT3XPlus, n = 10)

    ## Showing head and tail rows
    ##   RecordNo      AI
    ## 1 10:54:00   0.000
    ## 2 10:54:01   0.000
    ## 3 10:54:02   0.000
    ## 4 10:54:03   0.000
    ## 5 10:54:04 133.708
    ## 6 10:54:05  34.837
    ##    RecordNo      AI
    ## 5  10:54:04 133.708
    ## 6  10:54:05  34.837
    ## 7  10:54:06  62.947
    ## 8  10:54:07  54.207
    ## 9  10:54:08 124.708
    ## 10 10:54:09 147.842

We could also compute AI in different epoch. Say we want minute-by-minute AI, then we could use the following code

    AI_sampleTable_min = computeActivityIndex(sampleTable,
        sigma0 = sample_sigma0, epoch = 60, hertz = 30)
    AI_sampleGT3XPlus_min = computeActivityIndex(sampleGT3XPlus,
        sigma0 = sample_sigma0, epoch = 60, hertz = 30)

And according to the definition of AI, the minute-by-minute AI’s are simply the sum of all 1-second AI within each minute. The AI during the first \(6\) minutes are

    head(AI_sampleGT3XPlus_min)

    ## Showing head and tail rows
    ##   RecordNo       AI
    ## 1 10:54:00 3002.460
    ## 2 10:55:00  392.185
    ## 3 10:56:00  655.593
    ## 4 10:57:00   89.337
    ## 5 10:58:00  499.150
    ## 6 10:59:00  238.130
    ##   RecordNo       AI
    ## 1 10:54:00 3002.460
    ## 2 10:55:00  392.185
    ## 3 10:56:00  655.593
    ## 4 10:57:00   89.337
    ## 5 10:58:00  499.150
    ## 6 10:59:00  238.130