我正在尝试旋转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秒钟或更长时间来完成这种类型的操作。任何帮助将不胜感激!
答案 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
在此方法中,我有两个假设:
虽然这可能不是最优雅的解决方案,但它可以达到预期的结果,并且将处理数据所需的时间大大减少(从10s〜4k行减少到0.2s〜4k行)。如果有人能更好地应对这种情况并一口气完成上面概述的过程,那么我很乐意看到您的回应!