【问题标题】:ValueError when trying to have multi-index in DataFrame.pivot尝试在 DataFrame.pivot 中使用多索引时出现 ValueError
【发布时间】:2018-08-29 04:05:54
【问题描述】:

我已阅读pandas: how to run a pivot with a multi-index?,但它无法解决我的问题。

给定下面的数据框:

import pandas as pd
df = pd.DataFrame({
    "date": ["20180920"] * 6,
    "id": ["A123456789"] * 6,
    "test": ["a", "b", "c", "d", "e", "f"],
    "result": [70, 90, 110, "(-)", "(+)", 0.3],
    "ref": ["< 90", "70 - 100", "100 - 120", "(-)", "(-)", "< 1"]
})

我想传播test 列,使用result 中的值,并忽略ref。换句话说,期望的输出是这样的:

       date          id      a   b    c    d    e    f
0  20180920  A123456789     70  90  110  (-)  (+)  0.3

所以我尝试了df.pivot(index=["date", "id"], columns="test", values="result"),但它失败了 ValueError:传递值的长度是 6,索引意味着 2。我认为它与“如果传递一个数组,它必须与数据的长度相同”有关。在pivot_table documentation,但我就是不明白它的意思。有人可以详细说明一下吗?

顺便说一句,我终于通过df.drop(columns="ref").set_index(["date", "id", "test"]).unstack(level=2) 得到了我想要的输出。这是唯一正确的方法吗?

【问题讨论】:

标签: python pandas dataframe pivot


【解决方案1】:

pivot 不接受列列表作为索引,因此您需要使用 pivot_table。这里使用 first 的聚合是假设没有重复项。

pd.pivot_table(df,index=["date", "id"], columns="test", values="result", aggfunc= 'first')\
.reset_index().rename_axis(None, 1)

按照@piRsquared 的建议,使用 set_index 和 unstack 和 rename_axis 会更安全,

df.set_index(['date', 'id', 'test']).result.unstack()\
.reset_index().rename_axis(None, 1)

不管怎样,

    date    id          a   b   c   d   e   f
20180920    A123456789  70  90  110 (-) (+) 0.3

【讨论】:

  • 是的,成功了。您可以在末尾添加rename_axis(None, 1),但并非完全必要。
  • 嗯,首先应该有点危险,如果重复数据可能会丢失数据(并且不知道)
【解决方案2】:

pivot 可以使用,但是代码有点疯狂:

df = (df.set_index(["date", "id"])
        .pivot(columns="test")['result']
        .reset_index()
        .rename_axis(None, axis=1)
     )
print (df)

       date          id   a   b    c    d    e    f
0  20180920  A123456789  70  90  110  (-)  (+)  0.3

关于文档,您可以查看 issue 16578,在 pandas 0.24.0 中应该是 improved docs 或者可能是对使用 MultiIndex 的新支持? issue 8160也有点不清楚。

在我看来,您的最后一个代码应该只改进一点(与@Vaishali 相同的解决方案) - 通过在set_indexunstack 之后选择创建Series with MultiIndex 删除level,因为默认情况下是未堆叠的最后一级MultiIndex - Series.unstack:

level : int, string, 或者这些的列表,默认最后一级

要取消堆叠的关卡,可以传递关卡名称

#all 3 return same output
df.set_index(["date", "id", "test"])['result'].unstack()
df.set_index(["date", "id", "test"])['result'].unstack(level=2)
df.set_index(["date", "id", "test"])['result'].unstack(level=-1)

【讨论】:

  • 感谢这个解决方案,非常适合我
【解决方案3】:

使用pandas/issues/23955中定义的函数

def multiindex_pivot(df, columns=None, values=None):                                                                                                                        
    #https://github.com/pandas-dev/pandas/issues/23955                                                                                                                      
    names = list(df.index.names)                                                                                                                                            
    df = df.reset_index()                                                                                                                                                   
    list_index = df[names].values                                                                                                                                           
    tuples_index = [tuple(i) for i in list_index] # hashable                                                                                                                
    df = df.assign(tuples_index=tuples_index)                                                                                                                               
    df = df.pivot(index="tuples_index", columns=columns, values=values)                                                                                                     
    tuples_index = df.index  # reduced                                                                                                                                      
    index = pd.MultiIndex.from_tuples(tuples_index, names=names)                                                                                                            
    df.index = index                                                                                                                                                        
    return df                                                                                                                                                               

multiindex_pivot(df.set_index(['date', 'id']), columns='test', values='result')                                                                                            
Out[10]:                                                                                                                                                                            
test                  a   b    c    d    e    f                                                                                                                                     
date     id                                                                                                                                                                         
20180920 A123456789  70  90  110  (-)  (+)  0.3 

【讨论】:

    猜你喜欢
    • 2019-06-29
    • 1970-01-01
    • 2017-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-02
    • 1970-01-01
    相关资源
    最近更新 更多