The Python Heart Rate Analysis Toolkit is a module for heart rate analysis in Python. It started as pure-python implementation to analyse physiological data taken in naturalistisch driving and cycling experiments.
The module is described in my tutorial series:
- Analyzing a Discrete Heart Rate Signal Using Python - Part 1
- Analyzing a Discrete Heart Rate Signal Using Python - Part 2
- Analyzing a Discrete Heart Rate Signal Using Python - Part 3
- Analyzing a Discrete Heart Rate Signal Using Python - Part 4: in development
The module takes a discrete heart rate signal and outputs time-domain and frequency-domain measures often found in scientific literature:
Time domain:
- beats per minute, BPM
- interbeat interval, IBI
- standard deviation if intervals between adjacent beats, SDNN
- standard deviation of successive differences between adjacent R-R intervals, SDSD
- root mean square of successive differences between adjacend R-R intervals, RMSSD
- proportion of differences between R-R intervals greater than 20ms, 50ms, pNN20, pNN50
- median absolute deviation, MAD
Frequency domain
- low frequency component (0.04-0.15Hz), LF
- high frequency component (0.16-0.5Hz), HF
- lf/hf ratio, Lf/HF
Import the heartbeat module and load a file
import heartbeat as hb
hrdata = hb.get_data('yourdata.csv', column_name = 'hr')
This returns a numpy.ndarray.
Analysis requires the sampling rate for your data. If you know this a priori, supply it when calling the process() function, which returns a dict{} object containing all measures:
import heartbeat as hb
data = hb.get_data('yourdata.csv')
measures = hb.process(data, 100.0)
process(dataset, fs, hrw = 0.75) requires two arguments:
- dataset: An 1-dimensional list, numpy array or array-like object containing the heart rate data;
- fs: The samplerate of the signal in Hz;
- hrw: optional
hrwis the window size used for the calculation of the moving average. The windowsize is defined ashrw * samplerate. Default hrw = 0.75.
A dict{} object is returned containing all measures. The object is also stored in the module. Access as such:
import heartbeat as hb
data = hb.get_data('data.csv')
fs = 100.0 #example file 'data.csv' is sampled at 100.0 Hz
measures = hb.process(data, fs)
print(measures['bpm']) #returns BPM value
print(measures['lf/hf'] # returns LF:HF ratio
#Alternatively, use dictionary stored in module:
print(hb.measures['bpm']) #returns BPM value
print(hb.measures['lf/hf'] # returns LF:HF ratio
#You can also use Pandas if you so desire
import pandas as pd
df = pd.read_csv("data.csv")
measures = hb.process(df['hr'].values, fs)
print("measures['bpm'])
print("measures['lf/hf'])
The toolkit has functionality to open and parse delimited .csv and .txt files, as well as matlab .mat files. Opening a file is done by the get_data() function:
import heartbeat as hb
data = hb.get_data('data.csv')
This returns a 1-dimensional numpy.ndarray containing the heart rate data.
get_data(filename, delim = ',', column_name = 'None') requires one argument:
- filename: absolute or relative path to a valid (delimited .csv/.txt or matlab .mat) file;
- delim optional: when loading a delimited .csv or .txt file, this specifies the delimiter used. Default delim = ',';
- column_name optional: In delimited files with header: specifying column_name will return data from that column. Not specifying column_name for delimited files will assume the file contains only numerical data, returning np.nan values where data is not numerical. For matlab files: column_name specifies the table name in the matlab file.
Examples:
import heartbeat as hb
#load data from a delimited file without header info
headerless_data = hb.get_data('data.csv')
#load data from column labeles 'hr' in a delimited file with header info
headered_data = hb.get_data('data.csv', column_name = 'hr')
#load matlab file
matlabdata = hb.get_data('data2.mat', column_name = 'hr')
The toolkit has a simple built-in sample-rate detection. It can handle ms-based timers and datetime-based timers.
import heartbeat as hb
#if you have a ms-based timer:
fs = hb.get_samplerate_mstimer(mstimer_data)
#if you have a datetime-based timer:
fs = hb.get_samplerate_datetime(datetime_data, timeformat='%Y-%m-%d %H:%M:%s.%f')
get_samplerate_mstimer(timerdata) requires one argument:
- timerdata: a list, numpy array or array-like object containing ms-based timestamps (float or int).
get_samplerate_datetime(datetimedata, timeformat = '%H:%M:%S.f') requires one argument:
- datetimedata: a list, numpy array or array-like object containing datetime-based timestamps (string);
- timeformat optional: the format of the datetime-strings in datetimedata. Default timeformat = '%H:%M:%S.f', 24-hour based time including ms: 21:43:12.569.
A plotting function is included. It plots the original signal and overlays the detected peaks and the rejected peaks (if any were rejected).
Example with the included data.csv example file (recorded at 100.0Hz):
import heartbeat as hb
data = hb.get_data('data.csv')
measures = hb.process(data, 100.0)
hb.plotter()
This returns:
plotter(show = True, title = 'Heart Rate Signal Peak Detection') has two optional arguments:
- show optional: if set to True a plot is visualised, if set to False a matplotlib.pyplot object is returned. Default show = True;
- title optional: Sets the title of the plot. If not specified, default title is used.
Examples:
import heartbeat as hb
hrdata = hb.get_data('data2.csv', column_name = 'hr')
timerdata = hb.get_data('data2.csv., column_name = 'timer')
hb.process(dataset, hb.get_samplerate_mstimer(timerdata))
#plot with different title
hb.plotter(title='Heart Beat Detection on Noisy Signal')
Measures are only calculated for non-rejected peaks and intervals between two non-rejected peaks. Rejected detections do not influence the calculated measures.
By default a plot is visualised when plotter() is called. The function returns a matplotlib.pyplot object if the argument show=False is passed:
hb.process(dataset, 0.75, get_samplerate_mstimer(dataset))
hb.plotter(show=False)
This returns:
<module 'matplotlib.pyplot' from '<pythonpath>\lib\site-packages\matplotlib\pyplot.pyc'>
Object can then be saved or visualised:
hb.process(dataset, 0.75, get_samplerate_mstimer(dataset))
plot_object = hb.plotter(show=False)
plot_object.savefig('plot_1.jpg') #saves the plot as JPEG image.
plt.object.show() #displays plot
The module is licensed under the GNU General Public License Version3, GPL-v3
The module is still in active development. The to-do for the coming months is:
- Replace numerical work with numpy functions, to increase speed of processing
- Drop dependency on pandas
- Implement data handler function, recognising most used formats and parsing correctly
- Make values for inaccurate bpm rejection settable
- Increase versatility of sampling rate detection
- Improve accuracy of peak detection/rejection with an FFT-based implementation.
- Add MAD time-domain measure

