Demo notebook: Analysing battery data

Read data

[1]:
import pandas as pd
import niimpy
import niimpy.preprocessing.battery as battery
from niimpy import config
import warnings
warnings.filterwarnings("ignore")
[2]:
data = niimpy.read_csv(config.MULTIUSER_AWARE_BATTERY_PATH, tz='Europe/Helsinki')
data.shape
[2]:
(505, 8)

Introduction

In this notebook , we will extract battery data from the Aware platform and infer users’ behavioral patterns from their interaction with the phone. The below functions will be described in this notebook:

  • niimpy.preprocessing.battery.battery_shutdown_info: returns the timestamp when the device is shutdown or rebooted

  • niimpy.preprocessing.battery.battery_occurrences: returns the number of battery samples within a time range

  • niimpy.preprocessing.battery.battery_gaps: returns the time gaps between two battery sample

[3]:
data.head()
[3]:
user device time battery_level battery_status battery_health battery_adaptor datetime
2020-01-09 02:20:02.924999936+02:00 jd9INuQ5BBlW 3p83yASkOb_B 1.578529e+09 74 3 2 0 2020-01-09 02:20:02.924999936+02:00
2020-01-09 02:21:30.405999872+02:00 jd9INuQ5BBlW 3p83yASkOb_B 1.578529e+09 73 3 2 0 2020-01-09 02:21:30.405999872+02:00
2020-01-09 02:24:12.805999872+02:00 jd9INuQ5BBlW 3p83yASkOb_B 1.578529e+09 72 3 2 0 2020-01-09 02:24:12.805999872+02:00
2020-01-09 02:35:38.561000192+02:00 jd9INuQ5BBlW 3p83yASkOb_B 1.578530e+09 72 2 2 0 2020-01-09 02:35:38.561000192+02:00
2020-01-09 02:35:38.953000192+02:00 jd9INuQ5BBlW 3p83yASkOb_B 1.578530e+09 72 2 2 2 2020-01-09 02:35:38.953000192+02:00

Feature extraction

By default, Niimpy data should be ordered by the timestamp in ascending order. We start by sorting the data to make sure it’s compatible.

[4]:
data = data.sort_index()

Next, we will use Niimpy to extract features from the data. These are useful for inspecting the data and can be part of a full analysis workflow.

Usin the battery_occurences function, we can count the amount the battery samples every 10 minutes. This function requires the index to be sorted.

[5]:
battery.battery_occurrences(data, {"resample_args": {"rule": "10T"}})
[5]:
user device occurrences
2019-08-05 14:00:00+03:00 iGyXetHE3S8u Cq9vueHh3zVs 2
2019-08-05 14:10:00+03:00 iGyXetHE3S8u Cq9vueHh3zVs 0
2019-08-05 14:20:00+03:00 iGyXetHE3S8u Cq9vueHh3zVs 0
2019-08-05 14:30:00+03:00 iGyXetHE3S8u Cq9vueHh3zVs 1
2019-08-05 14:40:00+03:00 iGyXetHE3S8u Cq9vueHh3zVs 0
... ... ... ...
2020-01-09 22:50:00+02:00 jd9INuQ5BBlW OWd1Uau8POix 0
2020-01-09 23:00:00+02:00 jd9INuQ5BBlW OWd1Uau8POix 1
2020-01-09 23:10:00+02:00 jd9INuQ5BBlW OWd1Uau8POix 1
2020-01-09 23:20:00+02:00 jd9INuQ5BBlW OWd1Uau8POix 1
2020-01-09 23:30:00+02:00 jd9INuQ5BBlW OWd1Uau8POix 2

673 rows × 3 columns

The above dataframe gives the battery information of all users. You can also get the information for an individual by passing a filtered dataframe.

[6]:
f = niimpy.preprocessing.battery.battery_occurrences
data_filtered = data.query('user == "jd9INuQ5BBlW"')
individual_occurences = battery.extract_features_battery(data_filtered, features={f: {"resample_args": {"rule": "10T"}}})
individual_occurences.head()
<function battery_occurrences at 0x7fd7b27f2480> {'resample_args': {'rule': '10T'}}

[6]:
user device occurrences
2020-01-09 02:20:00+02:00 jd9INuQ5BBlW 3p83yASkOb_B 3
2020-01-09 02:30:00+02:00 jd9INuQ5BBlW 3p83yASkOb_B 5
2020-01-09 02:40:00+02:00 jd9INuQ5BBlW 3p83yASkOb_B 6
2020-01-09 02:50:00+02:00 jd9INuQ5BBlW 3p83yASkOb_B 6
2020-01-09 03:00:00+02:00 jd9INuQ5BBlW 3p83yASkOb_B 5

Next, you can extract the gaps between two consecutive battery samples with the battery_gaps function.

[7]:
f = niimpy.preprocessing.battery.battery_gaps
gaps = battery.battery_gaps(data, {})
gaps
[7]:
user device time battery_level battery_status battery_health battery_adaptor datetime
2019-08-05 14:00:58.600000+03:00 iGyXetHE3S8u Cq9vueHh3zVs 1.565003e+09 47 3 2 0 2019-08-05 14:00:58.600000+03:00
2019-08-05 14:03:35.800000+03:00 iGyXetHE3S8u Cq9vueHh3zVs 1.565003e+09 46 3 2 0 2019-08-05 14:03:35.800000+03:00
2019-08-05 14:30:54.196000+03:00 iGyXetHE3S8u Cq9vueHh3zVs 1.565005e+09 45 3 2 0 2019-08-05 14:30:54.196000+03:00
2019-08-05 15:22:06.193000192+03:00 iGyXetHE3S8u Cq9vueHh3zVs 1.565008e+09 44 3 2 0 2019-08-05 15:22:06.193000192+03:00
2019-08-05 16:21:29.716000+03:00 iGyXetHE3S8u Cq9vueHh3zVs 1.565011e+09 43 3 2 0 2019-08-05 16:21:29.716000+03:00
... ... ... ... ... ... ... ... ...
2020-01-09 23:02:13.938999808+02:00 jd9INuQ5BBlW OWd1Uau8POix 1.578604e+09 73 3 2 0 2020-01-09 23:02:13.938999808+02:00
2020-01-09 23:10:37.262000128+02:00 jd9INuQ5BBlW OWd1Uau8POix 1.578604e+09 73 3 2 0 2020-01-09 23:10:37.262000128+02:00
2020-01-09 23:22:13.966000128+02:00 jd9INuQ5BBlW OWd1Uau8POix 1.578605e+09 72 3 2 0 2020-01-09 23:22:13.966000128+02:00
2020-01-09 23:32:13.959000064+02:00 jd9INuQ5BBlW OWd1Uau8POix 1.578606e+09 71 3 2 0 2020-01-09 23:32:13.959000064+02:00
2020-01-09 23:39:06.800000+02:00 jd9INuQ5BBlW OWd1Uau8POix 1.578606e+09 71 3 2 0 2020-01-09 23:39:06.800000+02:00

505 rows × 8 columns

Knowing when the phone is shutdown is essential if we want to infer the usage behaviour of the subjects. This can be done by calling the shutdown_info function. The function returns the timestamp when the phone is shut down or rebooted (e.g: battery_status = -1).

[8]:
shutdown = battery.shutdown_info(data, config={'battery_column_name': 'battery_status'})
shutdown
[8]:
user device time battery_level battery_status battery_health battery_adaptor datetime
2019-08-07 10:37:11.308000+03:00 iGyXetHE3S8u Cq9vueHh3zVs 1.565163e+09 2 -1 2 0 2019-08-07 10:37:11.308000+03:00
2019-08-07 10:37:11.323000064+03:00 iGyXetHE3S8u Cq9vueHh3zVs 1.565163e+09 2 -1 2 0 2019-08-07 10:37:11.323000064+03:00

Extracting features with the extract_features call

We have seen above how to extract battery features using niimpy. Sometimes, we need more than one features and it would be inconvenient to extract everything one by one. niimpy provides a extract_feature call to allow you extracting all the features available and combining them into a single data frame. The extractable features must start with the prefix battery_.

[9]:
# Start by defining the feature name
f0 = niimpy.preprocessing.battery.battery_occurrences
f1 = niimpy.preprocessing.battery.battery_gaps
f2 = niimpy.preprocessing.battery.battery_charge_discharge

# The extract_feature function requires a features parameter.
# This parameter accepts a dictionary where the key is the feature name and value
# is a dictionary containing values passed to the function.
features = battery.extract_features_battery(
    data,
    features={f0: {'rule': "10min"},
    f1: {},
    f2: {}
})
features.head()
<function battery_occurrences at 0x7fd7b27f2480> {'rule': '10min'}
<function battery_gaps at 0x7fd7b27f2520> {}
<function battery_charge_discharge at 0x7fd7b27f25c0> {}

[9]:
user device occurrences time battery_level battery_status battery_health battery_adaptor datetime bdelta charge/discharge
2019-08-05 14:00:00+03:00 iGyXetHE3S8u Cq9vueHh3zVs 2.0 NaN NaN NaN NaN NaN NaT -0.5 -0.006361
2019-08-05 14:30:00+03:00 iGyXetHE3S8u Cq9vueHh3zVs 1.0 NaN NaN NaN NaN NaN NaT -1.0 -0.000610
2019-08-05 15:00:00+03:00 iGyXetHE3S8u Cq9vueHh3zVs 1.0 NaN NaN NaN NaN NaN NaT -1.0 -0.000326
2019-08-05 15:30:00+03:00 iGyXetHE3S8u Cq9vueHh3zVs 0.0 NaN NaN NaN NaN NaN NaT NaN NaN
2019-08-05 16:00:00+03:00 iGyXetHE3S8u Cq9vueHh3zVs 1.0 NaN NaN NaN NaN NaN NaT -1.0 -0.000281
[11]:
f1(data, {})
[11]:
user device time battery_level battery_status battery_health battery_adaptor datetime
2019-08-05 14:00:58.600000+03:00 iGyXetHE3S8u Cq9vueHh3zVs 1.565003e+09 47 3 2 0 2019-08-05 14:00:58.600000+03:00
2019-08-05 14:03:35.800000+03:00 iGyXetHE3S8u Cq9vueHh3zVs 1.565003e+09 46 3 2 0 2019-08-05 14:03:35.800000+03:00
2019-08-05 14:30:54.196000+03:00 iGyXetHE3S8u Cq9vueHh3zVs 1.565005e+09 45 3 2 0 2019-08-05 14:30:54.196000+03:00
2019-08-05 15:22:06.193000192+03:00 iGyXetHE3S8u Cq9vueHh3zVs 1.565008e+09 44 3 2 0 2019-08-05 15:22:06.193000192+03:00
2019-08-05 16:21:29.716000+03:00 iGyXetHE3S8u Cq9vueHh3zVs 1.565011e+09 43 3 2 0 2019-08-05 16:21:29.716000+03:00
... ... ... ... ... ... ... ... ...
2020-01-09 23:02:13.938999808+02:00 jd9INuQ5BBlW OWd1Uau8POix 1.578604e+09 73 3 2 0 2020-01-09 23:02:13.938999808+02:00
2020-01-09 23:10:37.262000128+02:00 jd9INuQ5BBlW OWd1Uau8POix 1.578604e+09 73 3 2 0 2020-01-09 23:10:37.262000128+02:00
2020-01-09 23:22:13.966000128+02:00 jd9INuQ5BBlW OWd1Uau8POix 1.578605e+09 72 3 2 0 2020-01-09 23:22:13.966000128+02:00
2020-01-09 23:32:13.959000064+02:00 jd9INuQ5BBlW OWd1Uau8POix 1.578606e+09 71 3 2 0 2020-01-09 23:32:13.959000064+02:00
2020-01-09 23:39:06.800000+02:00 jd9INuQ5BBlW OWd1Uau8POix 1.578606e+09 71 3 2 0 2020-01-09 23:39:06.800000+02:00

505 rows × 8 columns