簡體   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