繁体   English   中英

如何正确使用包含间隔的多索引的Pandas Dataframe?

[英]How can I properly use a Pandas Dataframe with a multiindex that includes Intervals?

我正在尝试切入具有由IntervalIndex和常规索引组成的MultiIndex的DataFrame。 示例代码:

from pandas import Interval as ntv

df = pd.DataFrame.from_records([
   {'id': 1, 'var1': 0.1, 'ntv': ntv(0,10), 'E': 1}, 
   {'id':2, 'var1': 0.5, 'ntv': ntv(0,12), 'E': 0}
], index=('ntv', 'id'))

看起来像这样:

            E  var1
ntv     id
(0, 10] 1   1   0.1
(0, 12] 2   0   0.5

我想要做的是以特定值切入DataFrame并返回具有包含该值的间隔的所有行。 例如:

df.loc[4]

应该回归(平凡)

    E  var1
id
1   1   0.1
2   0   0.5

问题是我不断收到关于索引的TypeError ,并且文档显示了类似的操作(但是在单级索引上),它确实产生了我正在寻找的东西。

TypeError: only integer scalar arrays can be converted to a scalar index

我尝试了很多东西,似乎没有什么能正常工作。 可以在数据帧中包含id列,但我宁愿保持我的索引唯一,我会不断调用set_index('id')

我觉得要么a)我缺少关于MultiIndexes的东西,或者b)在MultiIndex中使用IntervalIndex存在错误/歧义。

由于我们是发言间隔,因此有一个名为get_loc的方法来查找具有介于该间隔之间的值的行。 说出我的意思:

from pandas import Interval as ntv

df = pd.DataFrame.from_records([
   {'id': 1, 'var1': 0.1, 'ntv': ntv(0,10), 'E': 1}, 
   {'id':2, 'var1': 0.5, 'ntv': ntv(0,12), 'E': 0}
], index=('ntv', 'id'))

df.iloc[(df.index.get_level_values(0).get_loc(4))]
            E  var1
ntv     id         
(0, 10] 1   1   0.1
(0, 12] 2   0   0.5

df.iloc[(df.index.get_level_values(0).get_loc(11))]
             E  var1
ntv     id         
(0, 12] 2   0   0.5

如果您有一个inteval的多行数据,这也适用

df = pd.DataFrame.from_records([
   {'id': 1, 'var1': 0.1, 'ntv': ntv(0,10), 'E': 1}, 
   {'id': 3, 'var1': 0.1, 'ntv': ntv(0,10), 'E': 1},
   {'id':2, 'var1': 0.5, 'ntv': ntv(0,12), 'E': 0}
], index=('ntv', 'id'))

df.iloc[(df.index.get_level_values(0).get_loc(4))]

            E  var1
ntv     id         
(0, 10] 1   1   0.1
        3   1   0.1
(0, 12] 2   0   0.5

如果你用列表理解来计算时间,这种方法对于大型数据帧来说更快,即

ndf = pd.concat([df]*10000)

%%timeit
ndf.iloc[ndf.index.get_level_values(0).get_loc(4)]
10 loops, best of 3: 32.8 ms per loop

%%timeit
intervals = ndf.index.get_level_values(0)
mask = [4 in i for i in intervals]
ndf.loc[mask]
1 loop, best of 3: 193 ms per loop

所以我做了一些挖掘试图理解问题。 如果我尝试运行您的代码,则会发生以下情况。 您尝试使用“slice(array([0,1],dtype = int64),array([1,2],dtype = int64),None)索引索引标签”

(当我说index_type我指的是Pandas数据类型)

index_type的标签是映射到index_type的levels数组的索引列表。 以下是文档中的示例。

   >>> arrays = [[1, 1, 2, 2], ['red', 'blue', 'red', 'blue']]
    >>> pd.MultiIndex.from_arrays(arrays, names=('number', 'color'))
    MultiIndex(levels=[[1, 2], ['blue', 'red']],
           labels=[[0, 0, 1, 1], [1, 0, 1, 0]],
           names=['number', 'color'])

注意标签中的第二个列表如何连接到级别的顺序。 level [1] [1]等于红色,等级[1] [0]等于蓝色。

无论如何,这就是说我不相信intervalindex意味着以重叠的方式使用。 如果你看看它的原始提案https://github.com/pandas-dev/pandas/issues/7640

“IntervalIndex将是一个单调且不重叠的一维间隔阵列。”

我的建议是将间隔移动到一列。 您可以用numba编写一个简单的函数来测试每个区间中是否有数字。 你介意解释你从间隔中受益的方式吗?

Index.get_loc @ Dark的解决方案Index.get_loc只是在引擎盖下调用Index.get_indexer ,因此在没有其他参数和繁文缛节时调用底层方法可能更有效。

idx = df.index.get_level_values(0)
df.iloc[idx.get_indexer([4])]

我最初建议的解决方案

intervals = df.index.get_level_values(0)
mask = [4 in i for i in intervals]
df.loc[mask]

无论如何,虽然它们会返回两个不同的结果,但它看起来确实与索引是唯一的/单调的/两者都不相符,这当然很奇怪:

df.reset_index(level=1, drop=True).loc[4] # good
df.loc[4]  # TypeError

这不是一个真正的解决方案,我不完全理解,但认为它可能与你的间隔索引不单调(因为你有重叠的间隔)。 我想在某种意义上可以认为是单调的,所以也许你可以说重叠意味着指数不是唯一的?

无论如何,看看这个github问题:

ENH:实现MultiIndex.is_monotonic_decreasing#17455

以下是您的数据示例,但将间隔更改为非重叠(0,6)和(7,12):

df = pd.DataFrame.from_records([
   {'id': 1, 'var1': 0.1, 'ntv': ntv(0, 6), 'E': 1}, 
   {'id': 2, 'var1': 0.5, 'ntv': ntv(7,12), 'E': 0}
], index=('ntv', 'id'))

现在, loc工作正常:

df.loc[4]

    E  var1
id         
1   1   0.1
def check_value(num):
    return df[[num in i for i in map(lambda x: x[0], df.index)]] 

a = check_value(4)
a
>> 
            E  var1
ntv     id         
(0, 10] 1   1   0.1
(0, 12] 2   0   0.5  

如果要删除索引级别,可以添加

a.index = a.droplevel(0)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM