在数据框中的分组区域内滚动值

时间:2016-11-08 23:50:52

标签: python pandas numpy dataframe

考虑df

idx = map('first {}'.format, range(2)) + map('last {}'.format, range(3))
df = pd.DataFrame(np.arange(25).reshape(5, -1), idx, idx)
df

enter image description here

我想根据行和列标题中的文本将数据框分组为四个象限。这意味着左上象限由'first'列和'first'行组成。右上象限由'last'列和'first'行组成,依此类推。

然后在每个小组中,我想

  • 如果可以
  • 将每个元素向右滚动一个
  • 否则在开始的下一行开始,如果它可以
  • 否则从头开始

这应该有助于说明

enter image description here

预期输出应如下所示。

enter image description here

2 个答案:

答案 0 :(得分:3)

使用嵌套的groupby-apply模式和np.roll。对列执行groupby,然后在索引上执行groupby以获取要滚动的所需子组。然后使用np.roll执行roll,将输出包装在DataFrame中,因为np.roll只返回一个数组。

def roll_frame(df, shift):
    return pd.DataFrame(np.roll(df, shift), index=df.index, columns=df.columns)

# Groupers for the index and the columns.
idx_groups = df.index.map(lambda x: x.split()[0])
col_groups = df.columns.map(lambda x: x.split()[0])

# Nested groupby, then perform the roll..
df = df.groupby(col_groups, axis=1) \
       .apply(lambda grp: grp.groupby(idx_groups).apply(roll_frame, 1))

有点粗暴,但完成工作。您执行嵌套groupby的顺序并不重要。

结果输出:

         first 0  first 1  last 0  last 1  last 2
first 0        6        0       9       2       3
first 1        1        5       4       7       8
last 0        21       10      24      12      13
last 1        11       15      14      17      18
last 2        16       20      19      22      23

答案 1 :(得分:0)

我的解决方案

sdf = df.stack()
tups = sdf.index.to_series().apply(lambda x: tuple(pd.Series(x).str.split().str[0]))

sdf.groupby(tups).apply(lambda x: pd.Series(np.roll(x.values, 1), x.index)).unstack()

enter image description here