【问题标题】:Inconsistency between pandas xs and loc for repeated indices重复索引的熊猫 xs 和 loc 之间的不一致
【发布时间】:2018-02-16 07:05:03
【问题描述】:

为什么.loc 只返回单行,而多行具有相同的MultiIndex

给定以下数据框

           col0      col1  col2
idx0 idx1
0    0      1.0  example1   1.0
     0      4.0  example2   8.0
     1      9.0  example3  27.0
     1     16.0  example4  64.0
1    0      0.5  example1   0.5
     0      2.0  example2   4.0
     1      4.5  example3  13.5
     1      8.0  example4  32.0

.xs 操作将选择

In [121]: df.xs((0,1), level=[0,1])
Out[121]:
           col0      col1  col2
idx0 idx1
0    1      9.0  example3  27.0
     1     16.0  example4  64.0

.loc 操作将选择

In [125]: df.loc[[(0,1)]]
Out[125]:
           col0      col1  col2
idx0 idx1
0    1     16.0  example4  64.0

以下内容进一步强调了这一点

In [149]: df.loc[pd.IndexSlice[:, 1], :]
Out[149]:
           col0      col1  col2
idx0 idx1
0    1      9.0  example3  27.0
     1     16.0  example4  64.0

In [150]: df.loc[pd.IndexSlice[0, 1], :]
Out[150]:
col0          16
col1    example4
col2          64
Name: (0, 1), dtype: object

设置

import pandas as pd
import numpy as np
idx0 = range(2)
idx1 = np.repeat(range(2), 2)

midx = pd.MultiIndex(
    levels=[idx0, idx1],
    labels=[
        np.repeat(range(len(idx0)), len(idx1)),
        np.tile(range(len(idx1)), len(idx0))
    ],
    names=['idx0', 'idx1']
)

df = pd.DataFrame(
    [
        [i**2/float(j), 'example{}'.format(i), i**3/float(j)]
        for j in range(1, len(idx0) + 1)
        for i in range(1, len(idx1) + 1)
    ],
    columns=['col0', 'col1', 'col2'],
    index=midx
)

【问题讨论】:

标签: python pandas indexing multi-index


【解决方案1】:

使用.xs

df.xs((0,1), level=[0,1])
Out[74]: 
           col0      col1  col2
idx0 idx1                      
0    1      9.0  example3  27.0
     1     16.0  example4  64.0

使用.loc

df.loc[0].loc[1]
Out[75]: 
      col0      col1  col2
idx1                      
1      9.0  example3  27.0
1     16.0  example4  64.0

在二级索引中添加[]:(PS:link

df.loc[(0, [1]),:]

Out[90]: 
           col0      col1  col2
idx0 idx1                      
0    1      9.0  example3  27.0
     1     16.0  example4  64.0

【讨论】:

  • 这并不能真正回答问题......我有一个解决方法,我在问为什么.loc[[(0,1)]] 不起作用。非常感谢您提供进一步的示例,尽管这似乎只是强调了.loc[[(0,1)]] 的意外行为!
  • 你能解释一下为什么[1] 是必要的吗?这似乎很随意!
  • @AlexanderMcFarlane 检查链接pandas.pydata.org/pandas-docs/stable/…
  • 文档仍然没有显示为什么[1] 的行为应该与1 不同的示例。从根本上说,当df.loc[pd.IndexSlice[:, 1], :] 我得到所有重复但df.loc[pd.IndexSlice[0, 1], :] 只会返回一行。这实际上是一个非常好的例子,所以我将添加到 OP
【解决方案2】:

我不相信您的多索引创建正确。

df = df.assign(
    idx0=[0] * 4 + [1] * 4, 
    idx1=[0, 0, 1, 1] * 2).set_index(['idx0', 'idx1'])

使用loc 访问数据的正确方法之一:

>>> df.loc[(0, 1), :]
           col0      col1  col2
idx0 idx1                      
0    1        9  example3    27
     1       16  example4    64

在原始数据帧上使用相同的命令,我得到: TypeError: only integer arrays with one element can be converted to an index.

更新

正如我之前提到的,您似乎没有正确创建多索引。这个具有正确构建的多索引的数据框与您的示例一样工作(使用较旧的 pandas,v 0.17.2)。

midx = pd.MultiIndex.from_product([[0, 1], [0, 0, 1, 1]], names=['idx0', 'idx1'])
df = pd.DataFrame(
    [
        [i**2/float(j), 'example{}'.format(i), i**3/float(j)]
        for j in range(1, len(idx0) + 1)
        for i in range(1, len(idx1) + 1)
    ],
    columns=['col0', 'col1', 'col2'],
    index=midx)

使用上面定义的midx

>>> midx
MultiIndex(levels=[[0, 1], [0, 1]],
           labels=[[0, 0, 0, 0, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 1, 1]],
           names=[u'idx0', u'idx1'])

根据您的定义使用midx

>>> midx
MultiIndex(levels=[[0, 1], [0, 0, 1, 1]],
           labels=[[0, 0, 0, 0, 1, 1, 1, 1], [0, 1, 2, 3, 0, 1, 2, 3]],
           names=[u'idx0', u'idx1'])

【讨论】:

  • 问题中的df 有两个int64 索引,似乎它是“正确”创建的。你能解释一下为什么你的修改会像预期的那样表现吗?
  • 是的,我也遇到过。我将在底部的示例中使我的MultiIndex 创建更清洁。我压缩它以使我的帖子更短,但我和@BradSolomon 有同样的困惑
  • 感谢您的更新。这个问题是levels kwarg 中存在重复值的情况吗?如果levels 不能重复,熊猫库似乎应该抛出错误?
  • 虽然不明智,但数据框可以具有相同的列名。所以我相信levels 应该能够接受重复的一致性。
猜你喜欢
  • 2021-02-07
  • 1970-01-01
  • 1970-01-01
  • 2021-12-06
  • 2019-01-19
  • 2017-01-11
  • 2020-08-20
  • 2021-02-19
  • 2021-03-15
相关资源
最近更新 更多