def test_cwt(): # Load/format data src = os.path.abspath(__file__ + '/../../')+'/demo/demo_data.csv' raw_data = pd.read_csv(src, skiprows=99, names=['timestamps', 'x', 'y', 'z'], usecols=[0, 1, 2, 3]) raw_data = raw_data.iloc[3500:3700,:] raw_data['y'] = raw_data['y'] * 9.80665 # Run function being tested obtained_ic_peaks, obtained_fc_peaks = util._cwt(raw_data.y, 50, 5, 10) # Confirm expected results np.testing.assert_array_equal(obtained_ic_peaks, [10, 43, 75, 110, 141, 171]) np.testing.assert_array_equal(obtained_fc_peaks, [19, 50, 84, 117, 148, 179])
def extract_features(self, subject_height, subject_height_units='centimeter', sensor_height_ratio=0.53, result_file=None, classified_gait=None, ic_prom=5, fc_prom=25): ''' Continuous wavelet transform based method of gait feature detection optimization methods Parameters ---------- subject_height : int or float Height of the subject. Accepts centimeters by default. subject_height_units : str Units of provided subject height. Centimeters by default. - options: 'centimeter', 'inches', 'meter' sensor_height_ratio : float Height of the sensor relative to subject height. Calculated: sensor height / subject height result_file : str Optional argument that accepts .csv filepath string to save resulting gait feature dataframe to. None by default. (ie. myfolder/myfile.csv) classified_gait : str or pandas.core.frame.DataFrame Pandas dataframe containing results of gait bout classification procedure (classify_bouts) OR File path of .h5 file containing results of gait bout classification procedure (classify_bouts) ic_prom : int Prominance of initial contact peak detection fc_prom : int Prominance of final contact peak detection ''' import pandas as pd import gaitpy.util as util import warnings print('\tExtracting features...') # Load data y_accel, timestamps = util._load_data(self, self.down_sample) # If classified gait is provided, load pandas dataframe or h5 file if classified_gait is not None: if type(classified_gait) is str: gait_predictions = pd.read_hdf(classified_gait) elif type(classified_gait) is pd.core.frame.DataFrame: gait_predictions = classified_gait else: print( 'Unable to load classified gait: Please make sure the data is in the correct format, aborting...' ) return # Isolate gait bouts gait_windows = gait_predictions[gait_predictions['prediction'] == 1] if gait_windows.empty: print( 'The classified_gait data indicates no bouts of gait were detected, aborting...' ) return # Concatenate concurrent bouts gait_bouts = util._concatenate_windows(gait_windows, window_length=3) else: # if classified_gait is not provided, assume entire timeseries is 1 bout of gait start_time = timestamps[0].astype('datetime64[ms]') end_time = timestamps.iloc[-1].astype('datetime64[ms]') gait_bouts = pd.DataFrame( data={ 'start_time': [start_time], 'end_time': [end_time], 'bout_length': [(end_time - start_time).item().total_seconds()] }) all_bout_gait_features = pd.DataFrame() bout_n = 1 # Loop through gait bouts for row_n, bout in gait_bouts.iterrows(): bout_indices = ( timestamps.astype('datetime64[ms]') >= bout.start_time) & ( timestamps.astype('datetime64[ms]') <= bout.end_time) bout_data = pd.DataFrame([]) bout_data['y'] = pd.DataFrame( y_accel.loc[bout_indices].reset_index(drop=True)) bout_data['ts'] = timestamps.loc[bout_indices].reset_index( drop=True) if len(bout_data.y) < 15: warnings.warn('There are too few data points between ' + str(bout.start_time) + ' and ' + str(bout.end_time) + ', skipping bout...') continue # Run CWT Gait Model IC and FC detection ic_peaks, fc_peaks = util._cwt(bout_data.y, self.down_sample, ic_prom, fc_prom) # Run gait cycle optimization procedure pd.options.mode.chained_assignment = None optimized_gait = util._optimization(bout_data['ts'], ic_peaks, fc_peaks) if optimized_gait.empty or 1 not in list( optimized_gait.Gait_Cycle): continue # Calculate changes in height of the center of mass optimized_gait = util._height_change_com(optimized_gait, bout_data['ts'], bout_data['y'], self.down_sample) # Calculate gait features sensor_height = util._calculate_sensor_height( subject_height, subject_height_units, sensor_height_ratio) gait_features = util._cwt_feature_extraction( optimized_gait, sensor_height) # remove center of mass height and gait cycle boolean columns, remove rows with NAs gait_features.dropna(inplace=True) gait_features.drop(['CoM_height', 'Gait_Cycle', 'FC_opp_foot'], axis=1, inplace=True) gait_features.insert(0, 'bout_number', bout_n) gait_features.insert(1, 'bout_length_sec', bout.bout_length) gait_features.insert(2, 'bout_start_time', bout.start_time) gait_features.insert(5, 'gait_cycles', len(gait_features)) all_bout_gait_features = all_bout_gait_features.append( gait_features) bout_n += 1 all_bout_gait_features.reset_index(drop=True, inplace=True) all_bout_gait_features.iloc[:, 7:] = all_bout_gait_features.iloc[:, 7:].round( 3) # Save results if result_file: try: if not result_file.endswith('.csv'): result_file += '.csv' all_bout_gait_features.to_csv(result_file, index=False, float_format='%.3f') except: print( 'Unable to save data: Please make sure your results directory exists, aborting...' ) return if all_bout_gait_features.empty: print( '\tFeature extraction complete. No gait cycles detected...\n') else: print('\tFeature extraction complete!\n') return all_bout_gait_features