diff --git a/rowers/courses.py b/rowers/courses.py index 138cdffa..8a2b07df 100644 --- a/rowers/courses.py +++ b/rowers/courses.py @@ -72,6 +72,7 @@ def time_in_path(df,p,maxmin='max'): else: b = (~df['inpolygon']).shift(1)+df['inpolygon'] + if len(df[b==2]): return df[b==2]['time'].min(),df[b==2]['cum_dist'].min() @@ -247,9 +248,10 @@ def get_time_course(ws,course): rowdata = dataprep.getsmallrowdata_db( columns, ids = [w.id], - doclean=True, + doclean=False, workstrokesonly=False ) + rowdata.rename(columns = { ' latitude':'latitude', ' longitude':'longitude', diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 48f4556d..9f61de6f 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -56,7 +56,7 @@ import sys import utils import datautils -from utils import lbstoN,myqueue,is_ranking_piece +from utils import lbstoN,myqueue,is_ranking_piece,wavg from timezonefinder import TimezoneFinder @@ -2234,16 +2234,19 @@ def workout_rscore(w): df,row = getrowdata_db(id=w.id) df = clean_df_stats(df,workstrokesonly=False) + df['deltat'] = df['time'].diff() duration = df['time'].max()-df['time'].min() duration /= 1.0e3 - pwr4 = df['power']**(4.0) - normp = (pwr4.mean())**(0.25) + df['pwr4'] = df['power']**(4.0) + pwr4mean = wavg(df,'pwr4','deltat') + pwrmean = wavg(df,'power','deltat') + normp = (pwr4mean)**(0.25) if not np.isnan(normp): ftp = float(r.ftp) if w.workouttype in ('water','coastal'): ftp = ftp*(100.-r.otwslack)/100. - intensityfactor = df['power'].mean()/float(ftp) + intensityfactor = pwrmean/float(ftp) intensityfactor = normp/float(ftp) tss = 100.*((duration*normp*intensityfactor)/(3600.*ftp)) else: diff --git a/rowers/templates/workoutstats.html b/rowers/templates/workoutstats.html index e58f15a4..965a54f8 100644 --- a/rowers/templates/workoutstats.html +++ b/rowers/templates/workoutstats.html @@ -9,7 +9,9 @@

Workout Statistics for {{ workout.name }}

This is an experimental page which just lists a bunch of statistics for - your workout. This page is under rapid development. + your workout. The mean is of a metric is the mean with equal weight for + each stroke. The time weighted mean takes into account the stroke + duration.

@@ -55,6 +57,8 @@ Mean{{ value.mean|floatformat:-2 }} + + Time Weighted Mean {{ value.wmean|floatformat:-2 }} Minimum{{ value.min|floatformat:-2 }} diff --git a/rowers/utils.py b/rowers/utils.py index c10c873b..08f97d4b 100644 --- a/rowers/utils.py +++ b/rowers/utils.py @@ -319,3 +319,15 @@ def my_dict_from_instance(instance,model): thedict[fname] = (verbosename,value) return thedict + +def wavg(group, avg_name, weight_name): + """ http://stackoverflow.com/questions/10951341/pandas-dataframe-aggregate-function-using-multiple-columns + In rare instance, we may not have weights, so just return the mean. Customize this if your business case + should return otherwise. + """ + d = group[avg_name] + w = group[weight_name] + try: + return (d * w).sum() / w.sum() + except ZeroDivisionError: + return d.mean() diff --git a/rowers/views.py b/rowers/views.py index ad0fc39c..409ac0d5 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -754,7 +754,7 @@ from utils import ( geo_distance,serialize_list,deserialize_list,uniqify, str2bool,range_to_color_hex,absolute,myqueue,get_call, calculate_age,rankingdistances,rankingdurations, - is_ranking_piece,my_dict_from_instance + is_ranking_piece,my_dict_from_instance,wavg ) import datautils @@ -7446,7 +7446,7 @@ def workout_stats_view(request,id=0,message="",successmessage=""): return HttpResponseRedirect(url) datadf = dataprep.clean_df_stats(datadf,workstrokesonly=workstrokesonly) - + datadf['deltat'] = datadf['time'].diff() if datadf.empty: datadf,row = dataprep.getrowdata_db(id=id) @@ -7472,6 +7472,7 @@ def workout_stats_view(request,id=0,message="",successmessage=""): for field,verbosename in fielddict.iteritems(): thedict = { 'mean':datadf[field].mean(), + 'wmean': wavg(datadf, field, 'deltat'), 'min': datadf[field].min(), 'std': datadf[field].std(), 'max': datadf[field].max(), @@ -12687,7 +12688,7 @@ def plannedsession_view(request,id=0,rowerid=0, coursetimeseconds, coursemeters, coursecompleted - ) = courses.get_time_course(ws,ps.course) + ) = courses.get_time_course([w],ps.course) intsecs = int(coursetimeseconds) microsecs = int(1.e6*(coursetimeseconds-intsecs))