Python 将聚合函数应用于分层索引中多个索引的系统方法 问题

Python 将聚合函数应用于分层索引中多个索引的系统方法 问题,python,pandas,aggregate,multi-index,Python,Pandas,Aggregate,Multi Index,我希望有一个更系统的方法来聚合多个频率间隔的频率 以下数据帧包含表示时间频率数据的随机数据。其列索引包含以下级别: 条件 渠道 频率 生成数据帧的代码如下所示: 将numpy导入为np 作为pd进口熊猫 pidx=pd.indexlice D=np.零点((32,2,2,6))#时间点、条件、通道、频率 对于范围(6)中的i: D[:,0,0,i]=np.arange(i,i+32,1)#C0,ch01 D[:,0,1,i]=np.arange(i+1,i+32+1,1)#C0,ch02 D[:

我希望有一个更系统的方法来聚合多个频率间隔的频率

以下数据帧包含表示时间频率数据的随机数据。其列索引包含以下级别:

  • 条件
  • 渠道
  • 频率
  • 生成数据帧的代码如下所示:

    将numpy导入为np
    作为pd进口熊猫
    pidx=pd.indexlice
    D=np.零点((32,2,2,6))#时间点、条件、通道、频率
    对于范围(6)中的i:
    D[:,0,0,i]=np.arange(i,i+32,1)#C0,ch01
    D[:,0,1,i]=np.arange(i+1,i+32+1,1)#C0,ch02
    D[:,1,0,i]=np.arange(i+2,i+32+2,1)#C1,ch01
    D[:,1,1,i]=np.arange(i+3,i+32+3,1)#C1,ch02
    条件=['C0','C1']
    通道=[“ch{:02}”。np.arange(1,3)中i的格式(i)]
    频率=np.arange(1,7)
    #Columns多索引
    cidx=来自产品的pd.多索引([条件、频道、频率])
    #重塑为二维
    D=D.重塑((D.形状[0],-1))
    #创建数据帧
    df=pd.DataFrame(D,columns=cidx)
    
    当前解决方案 目前我做了以下工作

    fbands={
    “fb1”:[pidx[1:3]],
    “fb2”:[pidx[2:5]],
    “fb3”:[pidx[4:6]]
    }
    def频带平均值(df,fb):
    返回df.loc(axis=1)[:,:,fb].groupby(axis=1,level=[0,1]).mean()
    dffbands=dict((k,频带_平均值(df,fbands[k]),表示fbands中的k)
    df_结果=pd.concat(dffbands,轴=1)
    
    但是,对于后一种代码,列索引级别没有得到维护,更具体地说,
    df_result
    的第一级包含在
    fbands
    中定义的每个频率间隔的名称。我会通过交换列级别来解决这个问题,但这似乎很麻烦

    问题: 我想知道是否有一种更系统的方法,在保持列索引级别的同时,一次性将聚合函数应用于多个频率间隔。最后,columnindex的最后一级应该是

  • 条件
  • 渠道
  • 频率间隔名称(例如
    fb1
    fb2
    fb3

  • 我猜你是把频率分成两组。如果是,请尝试:

    # it's convenient to groupby over rows than 
    data = df.T.reset_index()
    data.rename(columns={'level_0':'condition', 
                         'level_1': 'channel',
                         'level_2': 'frequency'},
                inplace=True)
    
    # groupby and compute mean
    # review your frequency grouping here
    # change mapping frequency -> frequency_band_group
    new_df = data.groupby(['condition', 'channel',  (data.frequency-1)//2]).mean()
    new_df.drop('frequency', axis=1, inplace=True)
    
    # change name for frequency index
    new_df.index.rename('frequency_band', level=2, inplace=True)
    
    # change label for frequency band
    new_df.index.set_levels([conditions, channels, ['fb1','fb2','fb3']], inplace=True)
    
    # transform back to get multi-level columns:
    new_df.T
    
    new_df=data.groupby(['condition','channel',(data.frequency-1)//2]).mean()
    new_df.drop('frequency',axis=1,inplace=True)

    如果我没有弄错,我会这样做:

    fbands={
        'fb1' : [0,3],
        'fb2' : [2,5],
        'fb3' : [4,6]
    }
    
    for co_i in df.columns.levels[0]:
        for cha_i in df.columns.levels[1]:
            for k,v in fbands.items():
                df[co_i,cha_i,k] = df[co_i,cha_i,].T[v[0]:v[1]].mean()
    
    df['C0','ch01','fb1'] = df.loc(axis=1)[pd.IndexSlice['C0','ch01',['f1','f2','f3'],:]].mean(axis=1)
    
    更新:注意这里的切片不是基于标签的,因此您实际上需要
    v[0]-1:v[1]
    ;为了更清楚地说明这一点,我建议您简化您的
    df

    D=np.zeros((32,2,2,6))
    for i in range(6):
        D[:,0,0,i]=np.arange(i,i+32,1) # C0, ch01
        D[:,0,1,i]=np.arange(i+1,i+32+1,1) # C0, ch02
        D[:,1,0,i]=np.arange(i+2,i+32+2,1) # C1, ch01
        D[:,1,1,i]=np.arange(i+3,i+32+3,1) # C1, ch02
    
    使
    df.head(3)
    返回:

        C0                                                          C1                                                        
      ch01                          ch02                          ch01                          ch02                          
         1    2    3    4    5    6    1    2    3    4    5    6    1    2    3    4    5    6    1    2    3    4    5     6
    0  0.0  1.0  2.0  3.0  4.0  5.0  1.0  2.0  3.0  4.0  5.0  6.0  2.0  3.0  4.0  5.0  6.0  7.0  3.0  4.0  5.0  6.0  7.0   8.0
    1  1.0  2.0  3.0  4.0  5.0  6.0  2.0  3.0  4.0  5.0  6.0  7.0  3.0  4.0  5.0  6.0  7.0  8.0  4.0  5.0  6.0  7.0  8.0   9.0
    2  2.0  3.0  4.0  5.0  6.0  7.0  3.0  4.0  5.0  6.0  7.0  8.0  4.0  5.0  6.0  7.0  8.0  9.0  5.0  6.0  7.0  8.0  9.0  10.0
    
    这样,我们就可以真正验证我们的期望!我现在使用的是
    fbands
    作为数组,而不是dict,因此排序变得很好(也可以使用
    collections
    中的
    OrderedDict

    返回:

        C0                            C1                         
      ch01           ch02           ch01           ch02          
       fb1  fb2  fb3  fb1  fb2  fb3  fb1  fb2  fb3  fb1  fb2  fb3
    0  1.0  2.5  4.0  2.0  3.5  5.0  3.0  4.5  6.0  4.0  5.5  7.0
    1  2.0  3.5  5.0  3.0  4.5  6.0  4.0  5.5  7.0  5.0  6.5  8.0
    2  3.0  4.5  6.0  4.0  5.5  7.0  5.0  6.5  8.0  6.0  7.5  9.0
    
    现在,
    fb*
    列实际上反映了频率fb1:[1,2,3]、fb2:[2,3,4,5]和fb3:[4,5,6]的平均值,我希望您能这样做

    更新2: 请注意,如果您将频率设置为这样:

    frequencies = ["f{0}".format(i) for i in np.arange(1,7)]
    
    然后,您可以在
    ch01
    C0
    中创建频率的平均值
    'f1'、'f2'、'f3'
    ,如下所示:

    fbands={
        'fb1' : [0,3],
        'fb2' : [2,5],
        'fb3' : [4,6]
    }
    
    for co_i in df.columns.levels[0]:
        for cha_i in df.columns.levels[1]:
            for k,v in fbands.items():
                df[co_i,cha_i,k] = df[co_i,cha_i,].T[v[0]:v[1]].mean()
    
    df['C0','ch01','fb1'] = df.loc(axis=1)[pd.IndexSlice['C0','ch01',['f1','f2','f3'],:]].mean(axis=1)
    

    我不确定我是否遵循了
    fbands
    的逻辑。看起来
    pidx[1:3]
    pidx[2:5]
    重叠?@QuangHoang,频率间隔重叠是可以的。频率不是按大小为2的组分组的。示例中的频率组是任意的,但应能够采用任何范围。明确规定。另外,
    data.groupby(['condition'、'channel'、(data.frequency-1)//2]).mean()
    抛出
    TypeError:-:'str'和'int'不支持的操作数类型,因为它是从str类型中减去(和除以)的。您的第二次更新正是我要找的!非常感谢。