Given a large mutli-column Pandas dataframe, I would like to compute the rolling "k-mean" over a window of N elements as quickly as possible.
Here "k-mean" is defined as the mean of the N-2k elements of N which exclude the k largest and k smallest elements.
Example
Given the dataframe:
df = pandas.DataFrame(
{'A': [34, 78, -2, -96, 58, -34, 44, -50, 42],
'B': [-82, 28, 96, 46, 36, -34, -20, 10, -40]})
A B
0 34 -82
1 78 28
2 -2 96
3 -96 46
4 58 36
5 -34 -34
6 44 -20
7 -50 10
8 42 -40
With N=6 and k=1 the expected output is:
A B
0 NaN NaN
1 NaN NaN
2 NaN NaN
3 NaN NaN
4 NaN NaN
5 14.0 19.0
6 16.5 22.5
7 -10.5 18.0
8 0.5 -2.0
Attempt
My code that seems to do the required is:
def k_mean(s: pandas.Series, trim: int) -> float:
assert trim >= 0, f"Trim must not be negative, {trim} provided."
if trim == 0:
return s.mean()
return s.sort_values()[trim:-trim].mean()
df.rolling(window=6, axis=0).apply(k_mean, kwargs={'trim': 1})
My question: Is my code correct and if so, is there a faster way to achieve the same result, especially considering large multicolumn dataframes?
Perhaps there is a neat mathematical trick to help?
I'm not too concered about the handling of the starting period if it helps speed up performance, either is can be NaN until N or can grow to N once 2k+1 elements are in the window.