代码之家  ›  专栏  ›  技术社区  ›  Eleuterio

有没有办法让元组在Pandas中作为索引发挥作用?

  •  2
  • Eleuterio  · 技术社区  · 2 年前

    我想在Pandas中使用多索引,在每个级别上我都有一个嵌套的元组。我知道原则上我可以打开这个东西,但这会不那么清晰和烦人。通常,元组的元素(类名和一些参数)只有在一起才有意义,我想让它更难出现无意义的对,元组有不同的长度,我想使用MultiIndex.from_product。

    在创建DataFrame和访问值时,一切都很好,但在编写时,我得到了意想不到的结果。

    在一个简单的示例中,以下代码:

    import pandas as pd
    index=pd.MultiIndex.from_arrays([[("foo","spam"),("foo","spam")],[("bar","egg"),("bar","egg")],[("baz","bacon"),("pam","bacon")]])
    this_index = (("foo","spam"),("bar","egg"),("baz","bacon"))
    df = pd.DataFrame(index=index, columns=["value"])
    print(df)
    print(df.loc[this_index])
    df.loc[this_index]=0
    # df.loc[this_index,"value"]=0
    print(df)
    

    首先打印我期望的表(列值中有三个元组作为索引和NaN),然后打印正确检索到的值NaN,但在最后一行显示了两个额外的列,名为“bar”和“egg”,均设置为0:

                                        value  bar  egg
    (foo, spam) (bar, egg) (baz, bacon)     0  0.0  0.0
                           (pam, bacon)   NaN  NaN  NaN
    

    在这种情况下,使用注释行进行赋值会得到预期的结果。

    然而,在我的情况下,我需要“垃圾邮件”、“鸡蛋”和“培根”也是元组。 如果我更改上面代码中的第2行和第3行,则输入:

    index=pd.MultiIndex.from_arrays([[("foo",("spam",)),("foo",("spam",))],[("bar",("egg",)),("bar",("egg",))],[("baz",("bacon",)),("pam",("bacon",))]])
    this_index = (("foo",("spam",)),("bar",("egg",)),("baz",("bacon",)))
    

    我对前两张照片再次有了预期的行为,第三张照片给出了(现在不知何故是预期的):

                                                 value  bar  (egg,)
    (foo, (spam,)) (bar, (egg,)) (baz, (bacon,))     0  0.0     0.0
                                 (pam, (bacon,))   NaN  NaN     NaN
    

    但尝试与上述相同的解决方法会得到:

    ValueError: setting an array element with a sequence. The requested array has an inhomogeneous shape after 2 dimensions. The detected shape was (3, 2) + inhomogeneous part.
    

    我找不到任何方法来调整这个技巧。

    目前我找到的最好的解决方法是对元组使用str(),然后在需要时再次解析内容,但我觉得应该有更好的方法。我在这里找到的唯一线索是一条未回复的评论 this answer .

    2 回复  |  直到 2 年前
        1
  •  1
  •   mozway    2 年前

    如果我理解正确的话,您的问题在于以下作业:

    index=pd.MultiIndex.from_arrays([[("foo",("spam",)),("foo",("spam",))],[("bar",("egg",)),("bar",("egg",))],[("baz",("bacon",)),("pam",("bacon",))]])
    this_index = (("foo",("spam",)),("bar",("egg",)),("baz",("bacon",)))
    
    df = pd.DataFrame(index=index, columns=["value"])
    df.loc[this_index, 'value']=0
    

    可以使用列或索引的列表来解决:

    df.loc[this_index, ['value']] = 0
    
    # or
    df.loc[[this_index], 'value'] = 0
    

    输出

                                                 value
    (foo, (spam,)) (bar, (egg,)) (baz, (bacon,))     0
                                 (pam, (bacon,))   NaN
    
        2
  •  1
  •   Andrej Kesely    2 年前

    您可以使用 pd.IndexSlice :

    index=pd.MultiIndex.from_arrays([[("foo",("spam",)),("foo",("spam",))],[("bar",("egg",)),("bar",("egg",))],[("baz",("bacon",)),("pam",("bacon",))]])
    this_index = (
        (
            "foo",
            ("spam",),
        ),
        ("bar", ("egg",)),
        ("baz", ("bacon",)),
    )
    df = pd.DataFrame(index=index, columns=["value"])
    
    df.loc[pd.IndexSlice[this_index], :] = 0  # note the `:` for column selector (this will set 0 for all columns)
    print(df)
    

    打印:

                                                 value
    (foo, (spam,)) (bar, (egg,)) (baz, (bacon,))     0
                                 (pam, (bacon,))   NaN