2017-08-30 59 views
4

索引MultiIndex-ed DataFrame時,看起來.iloc假設您引用索引的「內部級別」,而.loc查看外部級別。帶MultiIndex'd DataFrame的`.loc`和`.iloc`

例如:

np.random.seed(123) 
iterables = [['bar', 'baz', 'foo', 'qux'], ['one', 'two']] 
idx = pd.MultiIndex.from_product(iterables, names=['first', 'second']) 
df = pd.DataFrame(np.random.randn(8, 4), index=idx) 

# .loc looks at the outer index: 

print(df.loc['qux']) 
# df.loc['two'] would throw KeyError 
       0  1  2  3 
second          
one -1.25388 -0.63775 0.90711 -1.42868 
two -0.14007 -0.86175 -0.25562 -2.79859 

# while .iloc looks at the inner index: 

print(df.iloc[-1]) 
0 -0.14007 
1 -0.86175 
2 -0.25562 
3 -2.79859 
Name: (qux, two), dtype: float64 

兩個問題:

首先,這是爲什麼?這是故意的設計決定嗎?

其次,我可以用.iloc來引用索引的外層,以產生下面的結果嗎?我知道我可以先找到get_level_values,然後.loc索引的最後一個成員,但是如果它可以更直接地完成,可以使用時髦的.iloc語法或專爲該案例設計的一些現有函數來找到索引的最後一個成員。

# df.iloc[-1] 
qux one  0.89071 1.75489 1.49564 1.06939 
     two -0.77271 0.79486 0.31427 -1.32627 
+0

該索引是一個模擬到表中的線性列表。你會發現在第二個例子中,索引'-1'實際上由_two_值組成:'Name:(qux,two)'。 'loc'允許引用一個完整的索引(例如'df.loc ['qux','two']')或部分索引,但它是有序的。你可以做一個'reset_index',並按照其他順序設置索引。 –

回答

1

是的,這是一個deliberate design decision

.iloc是一個嚴格的位置索引器,它根本不是就是結構 ,只是第一個實際的行爲。 ... .loc確實考慮到 帳戶級別的行爲。 [強調加]

所以在問題中給出的預期結果不可能以靈活的方式與.iloc。最近的解決方法,在幾個類似的問題時,是

print(df.loc[[df.index.get_level_values(0)[-1]]]) 
        0  1  2  3 
first second          
qux one -1.25388 -0.63775 0.90711 -1.42868 
     two -0.14007 -0.86175 -0.25562 -2.79859 

使用double brackets將保留一個指數水平。

0

您可以使用:

df.iloc[[6, 7], :] 
Out[1]: 
        0   1   2   3 
first second 
qux one -1.253881 -0.637752 0.907105 -1.428681 
     two -0.140069 -0.861755 -0.255619 -2.798589 

[6, 7]對應於這些線路的實際行的索引,你可以看到如下:

df.reset_index() 
Out[]: 
    first second   0   1   2   3 
0 bar one -1.085631 0.997345 0.282978 -1.506295 
1 bar two -0.578600 1.651437 -2.426679 -0.428913 
2 baz one 1.265936 -0.866740 -0.678886 -0.094709 
3 baz two 1.491390 -0.638902 -0.443982 -0.434351 
4 foo one 2.205930 2.186786 1.004054 0.386186 
5 foo two 0.737369 1.490732 -0.935834 1.175829 
6 qux one -1.253881 -0.637752 0.907105 -1.428681 
7 qux two -0.140069 -0.861755 -0.255619 -2.798589 

這也適用於df.iloc[[-2, -1], :]df.iloc[range(-2, 0), :]


編輯:把它變成一個更通用的解決方案

則有可能得到一個泛型函數:

def multindex_iloc(df, index): 
    label = df.index.levels[0][index] 
    return df.iloc[df.index.get_loc(label)] 

multiindex_loc(df, -1) 
Out[]: 
        0   1   2   3 
first second 
qux one -1.253881 -0.637752 0.907105 -1.428681 
     two -0.140069 -0.861755 -0.255619 -2.798589 


multiindex_loc(df, 2) 
Out[]: 
        0   1   2   3 
first second 
foo one  2.205930 2.186786 1.004054 0.386186 
     two  0.737369 1.490732 -0.935834 1.175829 
+0

尋找一個更通用的方法,因爲我會有不同長度的DataFrames –

+0

@BradSolomon:它應該如何與'df.iloc [-1]'進行比較? – FabienP

+0

關於相同...泛型(?)與'df。iloc [-1]'會理想 –