I want to aggregate time-series data based on several conditions.
Apart of grouping the data by a timespan and the "type"- column, I would like to count and sum only positive values in the respective groups.
Can this be done elegantly without using .filter or creating subsets beforehand, and merging the aggregate data after?
The following code has been corrected thanks to jezrael's answer below. However, you should check out his answer for a more performant solution. While I prefer "the style" of the solution that I took here, for my dataframe ~50k rows, his approach is far faster.
Sample data:
datelist = ['2021-01-01','2021-02-01','2021-03-01']
datelist = [pd.to_datetime(item) for item in datelist]
datelist = [item for item in datelist for _ in (range(5))]
valuelist = np.random.randint(-100,100,size=(15))
typelist = np.random.randint(0,3, size=(15))
df = pd.DataFrame(
{'values': valuelist,
'types': typelist
}, index = datelist)
print(df)
values types
2021-01-01 -91 2
2021-01-01 -32 1
2021-01-01 -88 1
2021-01-01 7 1
2021-01-01 -84 0
2021-02-01 -57 0
2021-02-01 -28 1
2021-02-01 -11 0
2021-02-01 -66 1
2021-02-01 -9 2
2021-03-01 55 2
2021-03-01 -10 0
2021-03-01 -89 1
2021-03-01 61 1
2021-03-01 -28 1
myagg = {
'values_sum' : ('values', 'sum'),
'values_positive_count' : ('values', lambda x: (x > 0).sum()), # counts positive values
'values_negative_count' : ('values', lambda x: (x < 0).sum()), # counts negative values
'values_negative_sum' : ('values', lambda x: ((x < 0)*x).sum()), # corrected the parenthesis thanks to jezraels input - works now
}
df_agg = df.groupby([pd.Grouper(freq='D'), pd.Grouper('type')]).agg(**myagg)
Desired result:
print(dfagg)
sum values_positive_count values_negative_count a_positive_sum
types
2021-01-01 0 106 3 0 0
1 -62 0 1 7
2 -4 0 1 0
2021-02-01 0 -97 0 2 0
1 12 1 1 0
2 58 1 0 0
2021-03-01 0 -35 1 1 0
1 111 2 0 55
2 85 1 0 61