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..294c65ed 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(),