Battery Data

Introduction

Battery data can be recorded by many devices, including smartphones and watches. Battery information can provide insight about activity and sleep patterns. It is also necessary to interpret other data recorded by the device.

Battery data includes information about when the device is shut down, if applicable.

Battery data is expected to have the following columns (column names can be different, but in that case they must be provided as parameters):

  • user: Subject ID

  • device: Device ID

  • battery_level: The charge level if the device as percentage of full charge.

  • battery_status: Integer indicator of device status. Fully documented at https://awareframework.com/battery/.

    • Status 2: charging

    • Status 3: discharging

    • Status 5: battery full

    • Status 4: not charging

    • Status 1: unknown

    • Status -1: shutdown

    • Status -2: rebooted

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

Read data

[1]:
import niimpy
import niimpy.preprocessing.battery as battery
from niimpy import config
import warnings
warnings.filterwarnings("ignore")
/u/24/rantahj1/unix/miniconda3/envs/niimpy/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm
[2]:
data = niimpy.read_csv(config.MULTIUSER_AWARE_BATTERY_PATH, tz='Europe/Helsinki')
data.head()
[2]:
user device time battery_level battery_status battery_health battery_adaptor datetime
2020-01-09 02:20:02.924999952+02:00 jd9INuQ5BBlW 3p83yASkOb_B 1.578529e+09 74 3 2 0 2020-01-09 02:20:02.924999952+02:00
2020-01-09 02:21:30.405999899+02:00 jd9INuQ5BBlW 3p83yASkOb_B 1.578529e+09 73 3 2 0 2020-01-09 02:21:30.405999899+02:00
2020-01-09 02:24:12.805999994+02:00 jd9INuQ5BBlW 3p83yASkOb_B 1.578529e+09 72 3 2 0 2020-01-09 02:24:12.805999994+02:00
2020-01-09 02:35:38.561000109+02:00 jd9INuQ5BBlW 3p83yASkOb_B 1.578530e+09 72 2 2 0 2020-01-09 02:35:38.561000109+02:00
2020-01-09 02:35:38.953000069+02:00 jd9INuQ5BBlW 3p83yASkOb_B 1.578530e+09 72 2 2 2 2020-01-09 02:35:38.953000069+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.

[3]:
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_occurrences function, we can count the amount the battery samples every 10 minutes. This function requires the index to be sorted.

[4]:
battery.battery_occurrences(data, resample_args = {"rule": "10min"})
[4]:
device user occurrences
2020-01-09 02:20:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 3
2020-01-09 02:30:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 5
2020-01-09 02:40:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 6
2020-01-09 02:50:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 6
2020-01-09 03:00:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 5
... ... ... ...
2019-08-08 23:50:00+03:00 i8jmoIuoe12Mo dvWdLQesv21a 6
2019-08-09 00:00:00+03:00 i8jmoIuoe12Mo dvWdLQesv21a 6
2019-08-09 00:10:00+03:00 i8jmoIuoe12Mo dvWdLQesv21a 6
2019-08-09 00:20:00+03:00 i8jmoIuoe12Mo dvWdLQesv21a 6
2019-08-09 00:30:00+03:00 i8jmoIuoe12Mo dvWdLQesv21a 4

1169 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.

[5]:
f = niimpy.preprocessing.battery.battery_occurrences
data_filtered = data.query('user == "jd9INuQ5BBlW"')
individual_occurrences = battery.extract_features_battery(data_filtered, features={f: {"resample_args": {"rule": "10min"}}})
individual_occurrences.head()
<function battery_occurrences at 0x734b8b358ea0> {'resample_args': {'rule': '10min'}}
[5]:
device user occurrences
2020-01-09 02:20:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 3
2020-01-09 02:30:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 5
2020-01-09 02:40:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 6
2020-01-09 02:50:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 6
2020-01-09 03:00:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 5

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

[6]:
f = niimpy.preprocessing.battery.battery_gaps
gaps = battery.battery_gaps(data)
gaps
[6]:
device user battery_gap
2020-01-09 02:00:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 0 days 00:01:23.293666680
2020-01-09 02:30:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 0 days 00:02:03.573882355
2020-01-09 03:00:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 0 days 00:02:09.004461526
2020-01-09 03:30:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 0 days 00:02:09.319333346
2020-01-09 04:00:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 0 days 00:00:39.763869565
... ... ... ...
2019-08-08 22:30:00+03:00 i8jmoIuoe12Mo dvWdLQesv21a 0 days 00:02:21.165571434
2019-08-08 23:00:00+03:00 i8jmoIuoe12Mo dvWdLQesv21a 0 days 00:01:35.393473687
2019-08-08 23:30:00+03:00 i8jmoIuoe12Mo dvWdLQesv21a 0 days 00:01:38.987111104
2019-08-09 00:00:00+03:00 i8jmoIuoe12Mo dvWdLQesv21a 0 days 00:01:40.123666670
2019-08-09 00:30:00+03:00 i8jmoIuoe12Mo dvWdLQesv21a 0 days 00:01:42.400250017

393 rows × 3 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).

[7]:
shutdown = battery.shutdown_info(data, battery_column_name = 'battery_status')
shutdown
[7]:
user device time battery_level battery_status battery_health battery_adaptor datetime
2019-08-07 10:37:11.308000088+03:00 dvWdLQesv21a i8jmoIuoe12Mo 1.565163e+09 2 -1 2 0 2019-08-07 10:37:11.308000088+03:00
2019-08-07 10:37:11.308000088+03:00 iGyXetHE3S8u Cq9vueHh3zVs 1.565163e+09 2 -1 2 0 2019-08-07 10:37:11.308000088+03:00
2019-08-07 10:37:11.322999954+03:00 dvWdLQesv21a i8jmoIuoe12Mo 1.565163e+09 2 -1 2 0 2019-08-07 10:37:11.322999954+03:00
2019-08-07 10:37:11.322999954+03:00 iGyXetHE3S8u Cq9vueHh3zVs 1.565163e+09 2 -1 2 0 2019-08-07 10:37:11.322999954+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_.

[ ]:
# 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 0x734b8b358ea0> {'rule': '10min'}
<function battery_gaps at 0x734b8b358f40> {}
<function battery_charge_discharge at 0x734b8b358fe0> {}
device user occurrences battery_gap charge/discharge bdelta
2020-01-09 02:00:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 3 0 days 00:01:23.293666680 -0.008794 -0.666667
2020-01-09 02:30:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 17 0 days 00:02:03.573882355 0.014987 0.764706
2020-01-09 03:00:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 13 0 days 00:02:09.004461526 0.008331 1.000000
2020-01-09 03:30:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 15 0 days 00:02:09.319333346 0.034008 0.133333
2020-01-09 04:00:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 46 0 days 00:00:39.763869565 0.000000 0.000000
[9]:
f1(data)
[9]:
device user battery_gap
2020-01-09 02:00:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 0 days 00:01:23.293666680
2020-01-09 02:30:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 0 days 00:02:03.573882355
2020-01-09 03:00:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 0 days 00:02:09.004461526
2020-01-09 03:30:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 0 days 00:02:09.319333346
2020-01-09 04:00:00+02:00 3p83yASkOb_B jd9INuQ5BBlW 0 days 00:00:39.763869565
... ... ... ...
2019-08-08 22:30:00+03:00 i8jmoIuoe12Mo dvWdLQesv21a 0 days 00:02:21.165571434
2019-08-08 23:00:00+03:00 i8jmoIuoe12Mo dvWdLQesv21a 0 days 00:01:35.393473687
2019-08-08 23:30:00+03:00 i8jmoIuoe12Mo dvWdLQesv21a 0 days 00:01:38.987111104
2019-08-09 00:00:00+03:00 i8jmoIuoe12Mo dvWdLQesv21a 0 days 00:01:40.123666670
2019-08-09 00:30:00+03:00 i8jmoIuoe12Mo dvWdLQesv21a 0 days 00:01:42.400250017

393 rows × 3 columns