假设我有一个
形式的透视数据框 Value Qty Code
Color Blue Green Red Blue Green Red Blue Green Red
Date
2017-07-01 0.0 1.1 0.0 0.0 12.0 0.0 0 abc 0
2017-07-03 2.3 1.3 0.0 3.0 1.0 0.0 cde abc 0
2017-07-06 0.0 0.0 1.4 0.0 0.0 1.0 0 0 cde
我有兴趣将日期重新采样为每周频率。我想在主要列的每个子列上执行以下转换:值:max,Qty:sum,Code = last。在正常的非MultiIndex数据帧df中,可以通过agg()函数执行以下操作。
df.resample('W').agg({"Value":"max", "Qty":"sum", "Code":"last"})
但是当我使用透视数据框进行尝试时,它并不像键那样。在没有明确指定所有子列的情况下,如何在多索引数据框中执行此操作?
预期输出
Value Qty Code
Color Blue Green Red Blue Green Red Blue Green Red
Date
2017-07-02 0.0 1.1 0.0 0.0 12.0 0.0 0 abc 0
2017-07-09 2.3 1.3 1.4 3.0 1.0 1.0 0 0 cde
要生成上述起始数据帧,请使用以下代码
from collections import OrderedDict
import pandas as pd
table = OrderedDict((
("Date", ["2017-07-01", "2017-07-03", "2017-07-03", "2017-07-6"]),
('Color',['Green', 'Blue', 'Green', 'Red']),
('Value', [1.1, 2.3, 1.3, 1.4]),
('Qty', [12, 3, 1, 1]),
('Code', ['abc', 'cde', 'abc', 'cde'])
))
d = pd.DataFrame(table)
p = d.pivot(index='Date', columns='Color')
p.index = pd.to_datetime(p.index)
p.fillna(0, inplace=True)
编辑:添加了所需的结果。
编辑2:我还试图创建一个字典来输入agg()函数,但是它出现了4级列标题。
dc = dict(zip(p.columns, map({'Value': 'max', 'Qty': 'sum', 'Code': 'last'}.get, [x[0] for x in p.columns])))
newp = p.resample('W').agg(dc)
答案 0 :(得分:1)
我相信你需要stack()
来避免MultiIndex
。似乎没有办法在level=0
或agg
对象的groupby
方法中指定resample
,因此这是我能够弄明白的唯一方法(让我知道这是不准确的):
p.stack().reset_index(level=1).groupby(pd.Grouper(freq='w')).agg({'Value': 'max', 'Qty': 'sum', 'Code': 'last'})
Qty Value Code
Date
2017-07-02 12.0 1.1 0
2017-07-09 5.0 2.3 code
Stack将沿着轴0将颜色带到index
,重置索引以将MultiIndex
转换为DateTimeIndex
,其余部分非常简单。
修改强>
这有用吗?
dic = {'Value': 'max', 'Qty': 'sum', 'Code': 'last'}
df = pd.DataFrame()
for i in p.columns.get_level_values(0).unique():
temp = p.xs(i, axis=1, level=0, drop_level=False).resample('W').agg(dic[i])
df = pd.concat([df, temp], axis=1)
df.columns=p.columns
df
Value Qty Code
Color Blue Green Red Blue Green Red Blue Green Red
Date
2017-07-02 0.0 1.1 0.0 0.0 12.0 0.0 0 abc 0
2017-07-09 2.3 1.3 1.4 3.0 1.0 1.0 0 0 cde
我不知道如何“失败证明”这种方法是如此谨慎使用。设置df.columns=p.columns
似乎是粗略的,但保持多指数一直是主要的挑战。如果我在levels=p.columns.levels
中设置pd.concat()
(这似乎更安全),它会将索引展平为元组,这些元组也可以解压缩为多索引。我已经用几种不同的方式对它进行了测试,看起来没问题。
答案 1 :(得分:1)
首先考虑组合分层列并按不同的列类型运行每周聚合:值,数量和代码。
# COMBINE THE LIST OF MULTI-LEVEL COLUMN (LIST OF TUPLES)
p.columns = [i[0]+i[1] for i in p.columns]
p.columns = p.columns.get_level_values(0)
# HORIZONTAL MERGE
out = pd.concat([p.resample('W').max()[[c for c in p.columns if 'Value' in c]],
p.resample('W').sum()[[c for c in p.columns if 'Qty' in c]],
p.resample('W').last()[[c for c in p.columns if 'Code' in c]]], axis=1)
print(out)
# ValueBlue ValueGreen ValueRed QtyBlue QtyGreen QtyRed CodeBlue CodeGreen CodeRed
# Date
# 2017-07-02 0.0 1.1 0.0 0.0 12.0 0.0 0 abc 0
# 2017-07-09 2.3 1.3 1.4 3.0 1.0 1.0 0 0 cde
要保留原始层次结构列,请在展平列级别之前保存列对象,然后在重新采样过程之后重新分配回列:
pvtcolumns = p.columns
# ...same code as above
out.columns = pvtcolumns
print(df)
# Value Qty Code
# Color Blue Green Red Blue Green Red Blue Green Red
# Date
# 2017-07-02 0.0 1.1 0.0 0.0 12.0 0.0 0 abc 0
# 2017-07-09 2.3 1.3 1.4 3.0 1.0 1.0 0 0 cde