绕过多列,每列中都有重复的值

时间:2019-07-22 22:29:23

标签: python pandas

我正在尝试旋转pandas数据框,但是数据遵循一种我似乎无法旋转的奇怪格式。数据的结构如下:

Date, Location, Action1, Quantity1, Action2, Quantity2, ... ActionN, QuantityN
<date>   1      Lights    10         CFloor     1        ...  Null     Null
<date2>  2      CFloor    2          CWalls     4        ...  CBasement 15 
<date3>  2      CWalls    7          CBasement  4        ...  NUll     Null

本质上,每个动作将始终具有附加的数量(可能为0),但是空动作将永远不会具有数量(数量将仅为空)。我尝试实现的格式如下:

       Lights    CFloor    CBasement   CWalls
1        10         1         0           0
2        0          2         19          11

行的索引成为位置,而列成为跨多个活动列发现的任何唯一操作。将数据汇总在一起时,每个行/列的值是与该操作关联的每个数量的总和(即Action1对应于Quantity1)。有没有办法用本地的熊猫枢轴功能做到这一点?

我当前的代码在所有活动列上进行了排序,以获取所有唯一活动的列表。它还将从“位置”列中获取所有唯一位置。一旦有了唯一的列,就创建一个空的数据框,并用零填充:

       Lights    CFloor    CBasement   CWalls
1        0         0         0            0
2        0         0         0            0

然后,我使用itertuples()方法遍历旧数据框(被告知它比iterrows()快得多)并填充新数据框。此空数据框充当模板,该模板存储在内存中,稍后填充。

#Creates a template from the dataframe
def create_template(df):
    act_cols = ['Activity01', 'Activity02', 'Activity03', 'Activity04']
    activities = df[act_cols]
    flat_acts = activities.values.ravel('K')
    unique_locations = pd.unique(df['Location'])
    unique_acts = pd.unique(flat_acts)
    pivot_template = pd.DataFrame(index=unique_locations, columns=unique_acts).fillna(0)
    return pivot_template


#Fills the template from the dataframe
def create_pivot(df, pivot_frmt):
    act_cols = ['Activity01', 'Activity02', 'Activity03', 'Activity04']
    quant_cols = ['Quantity01', 'Quantity02', 'Quantity03', 'Quantity04']

    for row in df.itertuples():
        for act, quantity in zip(act_cols, quant_cols):
            act_val = getattr(row, act)
            if pd.notna(act_val):
                quantity_val = getattr(row, quantity)
                location = getattr(row, 'Location')
                pivot_frmt.loc[location, act_val] += quantity_val
    return pivot_frmt

虽然我的解决方案有效,但是在处理大型数据集时它的速度非常慢,并且花费了10秒钟或更长时间来完成这种类型的操作。任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:0)

在尝试了多种熊猫功能(例如模拟多列融化和枢轴旋转)之后,我找到了一个对我有用的解决方案:

对于每个数量-活动对,我都会构建最终数据集的部分框架并将其存储在列表中。一旦解决了每对问题,我将得到多个数据帧,这些数据帧的行数均相同,但列数却可能不同。我通过简单地串联列来解决了这个问题,如果有重复的列,我将它们相加以获得最终结果。

def test_pivot(df):
    act_cols = ['Activity01', 'Activity02', 'Activity03', 'Activity04']
    quant_cols = ['Quantity01', 'Quantity02', 'Quantity03', 'Quantity04']
    dfs = []
    for act, quant in zip(act_cols, quant_cols):
        partial = pd.crosstab(index=df['Location'], columns=df[act], values=df[quant], aggfunc=np.sum).fillna(0)
        dfs.append(partial)

    finalDf = pd.concat(dfs, axis=1)
    finalDf = test.groupby(finalDf.columns, axis=1).sum()
    return finalDf

在此方法中,我有两个假设:

  1. 索引在所有部分数据帧中保持其顺序
  2. 所有部分数据帧中都有相等数量的索引

虽然这可能不是最优雅的解决方案,但它可以达到预期的结果,并且将处理数据所需的时间大大减少(从10s〜4k行减少到0.2s〜4k行)。如果有人能更好地应对这种情况并一口气完成上面概述的过程,那么我很乐意看到您的回应!