转置和聚合DataFrame

时间:2017-08-22 20:47:07

标签: python pandas

我有一个像这样的数据框

  name tag  time  val
0  ABC   A     1   10
0  ABC   A     1   12
1  ABC   B     1   12
1  ABC   B     1   14
2  ABC   A     2   11
3  ABC   C     2   12
4  DEF   B     3   10
5  DEF   C     3    9
6  GHI   A     4   14
7  GHI   B     4   12
8  GHI   C     5   10

每一行都是一个时间戳,显示该行中名称和标记之间的值。

我想要的是一个数据框,其中每一行显示每个时间戳的每个标记的平均值,如下所示:

  name  time     A     B     C
0  ABC     1  11.0  13.0   NaN
1  ABC     2  11.0   NaN  12.0
2  DEF     3   NaN  10.0   9.0
3  GHI     4  14.0  12.0   NaN
4  GHI     5   NaN   NaN  10.0

我可以通过nametime分组并每次都返回一个转置系列来成功实现这一目标:

def transpose_df(observation_df):
  ser = pd.Series()
  for tag in tags:
    ser[tag] = observation_df[observation_df['tag'] == tag]['val'].mean()
  return ser


tdf = df.groupby(['name', 'time']).apply(transpose_df).reset_index()

但这很慢。我觉得必须有一个更聪明的方法使用内置的转置/重塑工具,但我无法弄清楚。任何人都可以看到建议更好的选择吗?

3 个答案:

答案 0 :(得分:6)

In [175]: df.pivot_table(index=['name','time'], columns='tag', values='val').reset_index()
Out[175]:
tag name  time     A     B     C
0    ABC     1  11.0  13.0   NaN
1    ABC     2  11.0   NaN  12.0
2    DEF     3   NaN  10.0   9.0
3    GHI     4  14.0  12.0   NaN
4    GHI     5   NaN   NaN  10.0

答案 1 :(得分:5)

选项1

使用pivot_table

df.pivot_table(values='val',index=['name','time'],columns='tag',aggfunc='mean').reset_index()

输出:

tag name  time     A     B     C
0    ABC     1  11.0  13.0   NaN
1    ABC     2  11.0   NaN  12.0
2    DEF     3   NaN  10.0   9.0
3    GHI     4  14.0  12.0   NaN
4    GHI     5   NaN   NaN  10.0

选项2:

使用groupbyunstack

df.groupby(['name','time','tag']).agg('mean')['val'].unstack().reset_index()

输出:

tag name  time     A     B     C
0    ABC     1  11.0  13.0   NaN
1    ABC     2  11.0   NaN  12.0
2    DEF     3   NaN  10.0   9.0
3    GHI     4  14.0  12.0   NaN
4    GHI     5   NaN   NaN  10.0

选项3

使用set_indexmean以及unstack

df.set_index(['name','time','tag']).mean(level=[0,1,2])['val'].unstack().reset_index()

输出:

tag name  time     A     B     C
0    ABC     1  11.0  13.0   NaN
1    ABC     2  11.0   NaN  12.0
2    DEF     3   NaN  10.0   9.0
3    GHI     4  14.0  12.0   NaN
4    GHI     5   NaN   NaN  10.0

答案 2 :(得分:4)

您还可以分组然后取消堆叠(相当于数据透视表)。

>>> df.groupby(['name', 'time', 'tag'])['val'].mean().unstack('tag').reset_index()
tag name  time   A   B   C
0    ABC     1  11  13 NaN
1    ABC     2  11 NaN  12
2    DEF     3 NaN  10   9
3    GHI     4  14  12 NaN
4    GHI     5 NaN NaN  10

顺便说一句,transform用于保存原始数据框的形状,例如。

>>> df.assign(tag_mean=df.groupby(['name', 'time', 'tag'])['val'].transform(np.mean))
  name tag  time  val  tag_mean
0  ABC   A     1   10        11
0  ABC   A     1   12        11
1  ABC   B     1   12        13
1  ABC   B     1   14        13
2  ABC   A     2   11        11
3  ABC   C     2   12        12
4  DEF   B     3   10        10
5  DEF   C     3    9         9
6  GHI   A     4   14        14
7  GHI   B     4   12        12
8  GHI   C     5   10        10