Python 如何在具有受限前瞻性的组内计算cummin?

Python 如何在具有受限前瞻性的组内计算cummin?,python,pandas,Python,Pandas,旧的 给出以下示例: group value 5 1 10 2 5 3 10 4 10 5 7 6 7 7 7 8 7 9 5 10 我想计算cummax,但是,我想在分组之前先看2。这是应该得到的结果 group value 5 3 10 4 5 3 10 5 10 5 7 8 7 9 7 9 7 9 5 10

旧的

给出以下示例:

group value
 5     1
10     2
 5     3
10     4
10     5
 7     6
 7     7
 7     8
 7     9
 5    10
我想计算
cummax
,但是,我想在分组之前先看2。这是应该得到的结果

group value
 5     3
10     4
 5     3
10     5
10     5
 7     8
 7     9
 7     9
 7     9
 5    10
我如何用熊猫来计算呢

新的

我目前的方法如下(基于Ezer K的建议)。您对提高可读性/性能有何建议

def cum_func_lookahead(g, v, func1, func2, lookahead):
d = defaultdict(list)

result = [np.nan] * len(g)

def d_(g, v):
    d[g].append(v)
    if len(d[g]) > 1:
        d[g][-1] = func1(d[g][-2], d[g][-1])
    return d[g][-1]

for i in range(len(g)):
    lookahead_g = g[i:i+lookahead]
    lookahead_v = v[i:i+lookahead]

    mask = (lookahead_g == g[i])
    lookahead_v = lookahead_v[mask]

    max_v = func2(lookahead_v, axis=0)

    result[i] = d_(g[i], max_v)


result = np.asarray(result)
return result


result = np.asarray(result)
return result
表演:

LENGTH = 100000
g = np.random.randint(low=0, high=LENGTH/2, size=LENGTH)
v = np.random.rand(LENGTH, 40)
%timeit r1 = cum_func_lookahead(g, v, np.maximum, np.max, 3)
1 loop, best of 3: 2.18 s per loop

我的建议是迭代df,如果新的max确实大于旧的max,则更新新的max dict:

创建一个dict,其中键为组,值初始化为零:

max_dict = dict(zip(df.group.unique(),df.group.nunique()*[0]))
浏览df(原始数据帧)的行,向前看,必要时更新dict,并将当前最大值附加到列表中:

l = []
for t in df.iterrows():
    tmp_df = df.ix[t[0]:(t[0]+2)]
    tmp_df = tmp_df[tmp_df['group']==t[1]['group']]
    tmp_max =  max(tmp_df['value'].values)
    if tmp_max>max_dict[t[1]['group']]:
        max_dict[t[1]['group']] = tmp_max
    l.append( max_dict[t[1]['group']] )

df['com_max'] = l

    group   value   com_max
    0   5   1   3
    1   10  2   4
    2   5   3   3
    3   10  4   5
    4   10  5   5
    5   7   6   8
    6   7   7   9
    7   7   8   9
    8   7   9   9
    9   5   10  10

此解决方案首先对
group
进行分组,并为
apply
创建一个自定义函数,该函数迭代地为每个组提前选择最多2个索引,并找到该组子集的最大值,然后将帧重新排序回其原始顺序

def max2(x):
    max_vals = [x.loc[idx:idx+2, 'value'].max() for idx in x.index]
    return pd.Series(max_vals, index=x.index, name='value')

df.groupby('group').apply(max2).reset_index('group').reindex(df.index)
输出

   group  value
0      5      3
1     10      4
2      5      3
3     10      5
4     10      5
5      7      8
6      7      9
7      7      9
8      7      9
9      5     10
内置解决方案 另一种解决方案依赖于
rolling
方法的附加功能。
rolling
方法允许根据日期范围确定窗口大小。默认的窗口是一个常量,对于这个问题不起作用。但是,如果您将索引转换为datetimelike索引,那么您可以利用
滚动方法并按日期进行切片

令人烦恼的是,
rolling
方法没有前瞻性选项,因此必须首先反转数据帧

首先反转并创建一个新索引,以天为单位

df = df[::-1].reset_index(drop=True)
df.index = pd.to_timedelta(df.index, 'D')
这就产生了:

        group  value
0 days      5     10
1 days      7      9
2 days      7      8
3 days      7      7
4 days      7      6
5 days     10      5
6 days     10      4
7 days      5      3
8 days     10      2
9 days      5      1
然后使用Pandas内置的滚动方法生成与上面完全相同的数据帧

df.groupby('group')\
  .rolling('3D', min_periods=0)['value']\
  .max()\
  .reset_index(0)\
  .reindex(df.index)[::-1]\
  .reset_index(drop=True)

我在numpy重新实现了你的方法(见问题)。你有什么进一步改进的建议吗?