pandas索引和選擇
索引Index
Many of these methods or variants thereof are available on the objectsthat contain an index (Series/Dataframe) and those should most likely beused before calling these methods directly.
從series物件中找到某元素(行)對應的索引
(如果索引是從0開始的連續值,那就是行號了)
nodes_id_index = pd.Index(nodes_series) print(nodes_id_index.get_loc('u_3223_4017'[Find element's index in pandas Series]))
更多請參考[Index]
檢索/選擇
dataframe列選擇
和Series一樣,在DataFrame中的一列可以通過字典記法或屬性來檢索,返回Series:
In [43]: frame2['state'] In [44]: frame2.year one Ohio one 2000 two Ohio two 2001 three Ohio three 2002 four Nevada four 2001 five Nevada five 2002 Name: state Name: year
Note: 返回的Series包含和DataFrame相同的索引,並它們的 name 屬性也被正確的設定了。
dataframe選擇多列
lines = lines[[0, 1, 4]]或者lines = lines[['user', 'check-in_time', 'location_id']]
dataframe連續選擇多列
[0:len(decoded) - 1]
dataframe選擇最後一列
df[df.columns[-1]]
或者df.ix[:,-1]
dataframe行選擇
>>> dates = pd.date_range('20130101', periods=6)
df = pd.DataFrame(np.random.randn(6,4), index=dates, columns=list('ABCD'))
>>> dates
DatetimeIndex(['2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04',
'2013-01-05', '2013-01-06'],
dtype='datetime64[ns]', freq='D')
>>> df
A B C D
2013-01-01 2.036209 1.354010 -0.677409 -0.331978
2013-01-02 -1.403797 -1.094992 0.304359 -1.576272
2013-01-03 1.137673 0.636973 -0.746928 -0.606468
2013-01-04 0.833169 -2.575147 0.866364 1.337163
行可以直接通過[]選擇,只是必須是數字範圍或者字串範圍索引(不同於series只有數字或字串也可以):
Note: 結束索引在這兒是被包含的!!!不同於numpy中的ndarray和Python中的list的索引!!!
>>> df['2013-01-02':'2013-01-03']
A B C D
2013-01-02 -1.403797 -1.094992 0.304359 -1.576272
2013-01-03 1.137673 0.636973 -0.746928 -0.606468
>>> df[3:5]
series行選擇
時間序列資料的索引技術
pandas 最基本的時間序列型別就是以時間戳(TimeStamp)為 index 元素的 Series 型別。
Selection by Position ix和iloc
行也可以使用一些方法通過位置num或名字label來檢索,例如 ix索引成員(field){更多ix使用例項可參考後面的“索引,挑選和過濾”部分}。
Note: 提取特定的某列資料。Python中,可以使用iloc或者ix屬性,但是ix更穩定一些。
ix{行選;行列選}
In [45]: frame2.ix['three'] year 2002 state Ohio pop 3.6 debt NaN Name: three
df.ix[3]
A -0.976627
B 0.766333
C -1.043501
D 0.554586
Name: 2013-01-04 00:00:00, dtype: float64
假設我們需資料第一列的前5行:
df.ix[:,0].head()>>> df.ix[1:3, 0:3] #相當於
df.ix[1:3, ['A', 'B', 'C']]
A B C
2013-01-02 -1.403797 -1.094992 0.304359
2013-01-03 1.137673 0.636973 -0.746928
iloc{行選;行列選}
Select via the position of the passed integers
與ix, [], at的區別是,iloc[3]選擇是的資料第3行,而其它如ix[3]選擇的是索引為3的那一行!
In [32]: df.iloc[3] A 0.721555 B -0.706771 C -1.039575 D 0.271860 Name: 2013-01-04 00:00:00, dtype: float64
By integer slices, acting similar to numpy/python
In [33]: df.iloc[3:5,0:2] A B 2013-01-04 0.721555 -0.706771 2013-01-05 -0.424972 0.567020
By lists of integer position locations, similar to the numpy/python style
In [34]: df.iloc[[1,2,4],[0,2]] A C 2013-01-02 1.212112 0.119209 2013-01-03 -0.861849 -0.494929 2013-01-05 -0.424972 0.276232
For getting fast access to a scalar (equiv to the prior method)
In [38]: df.iat[1,1] Out[38]: -0.17321464905330858
Selection by Label僅通過label選擇行loc[]
For getting a cross section using a labelIn [26]: df.loc[dates[0]] A 0.469112 B -0.282863 C -1.509059 D -1.135632 Name: 2013-01-01 00:00:00, dtype: float64
Selecting on a multi-axis by label
In [27]: df.loc[:,['A','B']] A B 2013-01-01 0.469112 -0.282863 2013-01-02 1.212112 -0.173215 2013-01-03 -0.861849 -2.104569 2013-01-04 0.721555 -0.706771 2013-01-05 -0.424972 0.567020 2013-01-06 -0.673690 0.113648
最快的僅選擇單數值at[]
For getting fast access to a scalar (equiv to the prior method)
In [31]: df.at[dates[0],'A'] Out[31]: 0.46911229990718628
布林索引Boolean Indexing
Using a single column’s values to select data.
In [39]: df[df.A > 0] A B C D 2013-01-01 0.469112 -0.282863 -1.509059 -1.135632 2013-01-02 1.212112 -0.173215 0.119209 -1.044236 2013-01-04 0.721555 -0.706771 -1.039575 0.271860
A where operation for getting.
In [40]: df[df > 0] A B C D 2013-01-01 0.469112 NaN NaN NaN ...
過濾filtering
Using the isin() method for filtering:
In [41]: df2 = df.copy() In [42]: df2['E'] = ['one', 'one','two','three','four','three'] In [43]: df2 A B C D E 2013-01-01 0.469112 -0.282863 -1.509059 -1.135632 one 2013-01-02 1.212112 -0.173215 0.119209 -1.044236 one 2013-01-03 -0.861849 -2.104569 -0.494929 1.071804 two 2013-01-04 0.721555 -0.706771 -1.039575 0.271860 three 2013-01-05 -0.424972 0.567020 0.276232 -1.087401 four 2013-01-06 -0.673690 0.113648 -1.478427 0.524988 three In [44]: df2[df2['E'].isin(['two','four'])] Out[44]: A B C D E 2013-01-03 -0.861849 -2.104569 -0.494929 1.071804 two 2013-01-05 -0.424972 0.567020 0.276232 -1.087401 four
索引,挑選和過濾
大多具體的索引規則見前面的“檢索/選擇”部分Series索引和整數索引
Series索引( obj[...] )的工作原理類似與NumPy索引,除了可以使用Series的索引值,也可以僅使用整數索引。
In [102]: obj = Series(np.arange(4.), index=['a', 'b', 'c', 'd']) In [103]: obj['b'] In [104]: obj[1] Out[103]: 1.0 Out[104]: 1.0 In [105]: obj[2:4] In [106]: obj[['b', 'a', 'd']] Out[105]: Out[106]: c 2 b 1 d 3 a 0 d 3 In [107]: obj[[1, 3]] In [108]: obj[obj < 2] b 1 a 0 d 3 b 1
整數索引
操作由整數索引的pandas物件跟內建的Python資料結構 (如列表和元組)在索引語義上有些不同。
例如,你可能認為下面這段程式碼不會產生一個錯誤:
ser = pd.Series(np.arange(3.))
ser
Out[11]:
0 0.0
1 1.0
2 2.0
dtype: float64
ser[-1]
這裡,有一個含有0,1,2的索引,很難推斷出使用者想要什麼(基於標籤或位置的索引);相反,一個非整數索引,就沒有這樣的歧義:
>>>ser2 = pd.Series(np.arange(3.), index=['a', 'b', 'c'])
>>>ser2[-1]
2.0
為了保持良好的一致性,如果軸索引含有索引器,那麼根據整數進行資料選取的操作將總是面向標籤的。這也包括用ix進行切片:
ser.ix[:1]
Out[15]:
0 0.0
1 1.0
dtype: float64
Series的iget_ value 方法、DataFrame 的 irow 和 icol 方法
如果你需要可靠的、不考慮索引型別的、基於位置的索引,可以使用Series的iget_ value 方法和 DataFrame 的 irow 和 icol 方法:
>>> ser3 = pd.Series(range(3), index=[-5, 1, 3])
>>> ser3.iget_value(2)
2
>>> frame = pd.DataFrame(np.arange(6).reshape(3, 2), index=[2,0,1])
frame
Out[21]:
0 1
2 0 1
0 2 3
1 4 5
>>> frame.irow(0)
0 0
1 1
Name: 2, dtype: int32
標籤切片
使用標籤來切片和正常的Python切片並不一樣,它會把結束點也包括在內:
In [109]: obj['b':'c'] b 1 c 2
索引賦值
使用這些函式來賦值
In [110]: obj['b':'c'] = 5 In [111]: obj a 0 b 5 c 5 d 3
通過切片或一個布林陣列來選擇行,這旨在在這種情況下使得DataFrame的語法更像一個ndarry。
In [116]: data[:2] In [117]: data[data['three'] > 5] one two three four one two three four Ohio 0 1 2 3 Colorado 4 5 6 7 Colorado 4 5 6 7 Utah 8 9 10 11 New York 12 13 14 15
DataFrame行標籤索引 ix
DataFrame可以在行上進行標籤索引,使你可以從DataFrame選擇一個行和列的子集,使用像NumPy的記法再加上軸標籤。這也是一種不是很冗長的重新索引的方法:
因此,有很多方法來選擇和重排包含在pandas物件中的資料。
DataFrame方法的簡短概要
還有分層索引及一些額外的選項。
obj[val] | 從DataFrame選擇單一列或連續列。特殊情況下的便利:布林陣列(過濾行),切片(行切片),或布林DataFrame(根據一些標準來設定值)。 |
---|---|
obj.ix[val] | 從DataFrame的行集選擇單行 |
obj.ix[:, val] | 從列集選擇單列 |
obj.ix[val1, val2] | 選擇行和列 |
reindex 方法 | 轉換一個或多個軸到新的索引 |
xs 方法 | 通過標籤選擇單行或單列到一個Series |
icol, irow 方法 | 通過整數位置,分別的選擇單行或單列到一個Series |
get_value, set_value 方法 | 通過行和列標選擇一個單值 |
Note:在設計pandas時,我覺得不得不敲下 frame[:, col] 來選擇一列,是非常冗餘的(且易出錯的),因此列選擇是最常見的操作之一。因此,我做了這個設計權衡,把所有的富標籤索引引入到ix 。
唯一值、值計數以及成員資格
唯一值、值計數、成員資格方法
方法 說明
isin 計算一個表示“Series各值是否包含於傳入的值序列中”的布林型陣列
unique 計算Series中的唯一值陣列,按發現的順序返回
value_counts 返回一個Series,其索引為唯一值,其值為頻率,按計數值降序排列
這類方法可以從一維Series的值中抽取資訊。
isin
用於判斷向量化集合的成員資格,可用於選取Series中或DataFrame列中 資料的子集:
>>> obj
0 c
1 a
2 d
3 a
4 a
5 b
6 b
7 c
8 c
dtype: object
>>>mask=obj.isin(['b','c'])
>>> mask
0 True...
8 True
dtype: bool
>>> obj[mask]
0 c
5 b
6 b
7 c
8 c
>>> obj=Series(['c','a','d','a','a','b','b','c','c'])
obj.unique()
# 函式是unique,它可以得到Series中的唯一值陣列:
>>>uniques = obj.unique()
>>>uniques
array(['c', 'a', 'd', 'b'], dtype=object)
返冋的唯一值是未排序的,如果需要的話,可以對結果再次進行排序(uniques. sort())。
value_counts
用於計算一個Series中各值出現的頻率:
>>> obj.value_counts()
c 3
a 3
b 2
d 1
dtype: int64
為了便於査看,結果Series是按值頻率降序排列的。
查原始碼,發現這個統計是通過hashtable實現的。keys, counts = htable.value_count_scalar64(values, dropna)
統計陣列或序列所有元素出現次數pd.value_counts
value_counts還是一個頂級pandas方法,可用於任何陣列或序列:
>>> pd.value_counts(obj.values, sort=False)
a 3
c 3
b 2
d 1
dtype: int64
返回一個pandas.series物件,不過你基本可以將它當成dict一樣使用。
當然也可以減去一些判斷,直接使用pandas.value_counts()呼叫的hashtable統計方法(lz在原始碼中看到的)
import pandas.hashtable as htable values = np.array([1, 2, 3, 5, 1, 3, 3, 2, 3, 5]) values_cnts = dict(zip(*htable.value_count_scalar64(values, dropna=True))) print(values_cnts)
apply應用於DataFrame
有時,可能希望得到DataFrame中多個相關列的一張柱狀圖。例如:
>>>data = pd.DataFrame({'Qu1': [1, 3, 4, 3, 4],'Qu2': [2, 3, 1, 2, 3],'Qu3': [1, 5, 2, 4, 4]})
>>>data
Qu1 Qu2 Qu3
0 1 2 1
1 3 3 5
2 4 1 2
3 3 2 4
4 4 3 4
將 pandas.value_counts 傳給該 DataFrame 的 apply 函式:
In[25]: data.apply(pd.value_counts).fillna(0)
Qu1 Qu2 Qu3
1 1.0 1.0 1.0
2 0.0 2.0 1.0
3 2.0 2.0 0.0
4 2.0 0.0 2.0
5 0.0 0.0 1.0
索引物件obj.index
pandas的索引物件用來儲存座標軸標籤和其它元資料(如座標軸名或名稱)。構建一個Series或DataFrame時任何陣列或其它序列標籤在內部轉化為索引:
In [68]: obj = Series(range(3), index=['a', 'b', 'c']) In [69]: index = obj.index In [70]: index Out[70]: Index([a, b, c], dtype=object) In [71]: index[1:] Out[71]: Index([b, c], dtype=object)
不可變性
索引物件是不可變的,因此不能由使用者改變:
In [72]: index[1] = 'd' Exception Traceback (most recent call last)... Exception: <class 'pandas.core.index.Index'> object is immutable
索引物件的不可變性非常重要,這樣它可以在資料結構中結構中安全的共享:
In [73]: index = pd.Index(np.arange(3)) In [74]: obj2 = Series([1.5, -2.5, 0], index=index) In [75]: obj2.index is index Out[75]: True
pandas中的主要索引物件
表格 是庫中內建的索引類清單。通過一些開發努力,索引可以被子類化,來實現特定座標軸索引功能。多數使用者不必要知道許多索引物件的知識,但是它們仍然是pandas資料模型的重要部分。
Index | 最通用的索引物件,使用Python物件的NumPy陣列來表示座標軸標籤。 |
---|---|
Int64Index | 對整形值的特化索引。 |
MultiIndex | “分層”索引物件,表示單個軸的多層次的索引。可以被認為是類似的元組的陣列。 |
DatetimeIndex | 儲存納秒時間戳(使用NumPy的datetime64 dtyppe來表示)。 |
PeriodIndex | 對週期數據(時間間隔的)的特化索引。 |
固定大小集合功能
除了類似於陣列,索引也有類似固定大小集合一樣的功能
In [76]: frame3 state Nevada Ohio year 2000 NaN 1.5 2001 2.4 1.7 2002 2.9 3.6 In [77]: 'Ohio' in frame3.columns Out[77]: True In [78]: 2003 in frame3.index Out[78]: False
索引方法和屬性
每個索引都有許多關於集合邏輯的方法和屬性,且能夠解決它所包含的資料的常見問題。
append | 連結額外的索引物件,產生一個新的索引 |
---|---|
diff | 計算索引的差集 |
intersection | 計算交集 |
union | 計算並集 |
isin | 計算出一個布林陣列表示每一個值是否包含在所傳遞的集合裡 |
delete | 計算刪除位置i的元素的索引 |
drop | 計算刪除所傳遞的值後的索引 |
insert | 計算在位置i插入元素後的索引 |
is_monotonic | 返回True,如果每一個元素都比它前面的元素大或相等 |
is_unique | 返回True,如果索引沒有重複的值 |
unique | 計算索引的唯一值陣列 |
重建索引reindex
pandas物件的一個關鍵的方法是 reindex ,意味著使資料符合一個新的索引來構造一個新的物件。
reindex更多的不是修改pandas物件的索引,而只是修改索引的順序,如果修改的索引不存在就會使用預設的None代替此行。且不會修改原陣列,要修改需要使用賦值語句。
index | 作為索引的新序列。可以是索引例項或任何類似序列的Python資料結構。一個索引被完全使用,沒有任何拷貝。 |
---|---|
method | 插值(填充)方法,見表格5-4的選項 |
fill_value | 代替重新索引時引入的缺失資料值 |
limit | 當前向或後向填充時,最大的填充間隙 |
level | 在多層索引上匹配簡單索引,否則選擇一個子集 |
copy | 如果新索引與就的相等則底層資料不會拷貝。預設為True(即始終拷貝) |
In [79]: obj = Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c']) In [80]: obj d 4.5 b 7.2 a -5.3 c 3.6
reindex 重排資料(行索引)
在Series上呼叫 reindex 重排資料,使得它符合新的索引,如果那個索引的值不存在就引入缺失資料值:
In [81]: obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e'])
In [82]: obj2
a -5.3
b 7.2
c 3.6
d 4.5
e NaN
In [83]: obj.reindex(['a', 'b', 'c', 'd', 'e'], fill_value=0)
a -5.3
b 7.2
c 3.6
d 4.5
e 0.0
重建索引的內插或填充method
為了對時間序列這樣的資料排序,當重建索引的時候可能想要對值進行內插或填充。 method 選項可以是你做到這一點,使用一個如ffill 的方法來向前填充值:
In [84]: obj3 = Series(['blue', 'purple', 'yellow'], index=[0, 2, 4]) In [85]: obj3.reindex(range(6), method='ffill') 0 blue 1 blue 2 purple 3 purple 4 yellow 5 yellow
method 選項的清單
引數 | 描述 |
---|---|
ffill或pad | 前向(或進位)填充 |
bfill或backfill | 後向(或進位)填充 |
對於DataFrame, reindex 可以改變(行)索引,列或兩者。當只傳入一個序列時,結果中的行被重新索引了:
In [86]: frame = DataFrame(np.arange(9).reshape((3, 3)), index=['a', 'c', 'd'], columns=['Ohio', 'Texas', 'California']) In [87]: frame Ohio Texas California a 0 1 2 c 3 4 5 d 6 7 8
列重新索引關鍵字columns
使用 columns 關鍵字可以是列重新索引:
In [90]: states = ['Texas', 'Utah', 'California'] In [91]: frame.reindex(columns=states) Texas Utah California a 1 NaN 2 c 4 NaN 5 d 7 NaN 8
DataFrame重新命名列columns方法2:
df.rename(columns={'age': 'x', 'fat_percent': 'y'})
行列同時重新索引2種方式
一次可以對兩個重新索引,可是插值只在行側(0座標軸)進行:
In [92]: frame.reindex(index=['a', 'b', 'c', 'd'], method='ffill', columns=states) Texas Utah California a 1 NaN 2 b 1 NaN 2 c 4 NaN 5 d 7 NaN 8
正如你將看到的,使用帶標籤索引的 ix 可以把重新索引做的更簡單:
In [93]: frame.ix[['a', 'b', 'c', 'd'], states] Texas Utah California a 1 NaN 2 b NaN NaN NaN c 4 NaN 5 d 7 NaN 8
DataFrame索引和列的互轉set_index reset_index
人們經常想要將DataFrame的一個或多個列當做行索引來用,或者可能希望將行索引變成DataFrame的列。以下面這個DataFrame為例:frame = pd.DataFrame({'a': range(7),'b': range(7, 0, -1),'c': ['one','one','one','two','two','two', 'two'],'d': [0, 1, 2, 0, 1, 2, 3]})
frame
a b c d
0 0 7 one 0
1 1 6 one 1
2 2 5 one 2
3 3 4 two 0
4 4 3 two 1
5 5 2 two 2
6 6 1 two 3
列轉換為行索引set_index
DataFrame的set_index函式會將其一個或多個列轉換為行索引,建立一個新的 DataFrame :frame2 = frame.set_index(['c', 'd'])
In [6]: frame2
a b
c d
one 0 0 7
1 1 6
2 2 5
two 0 3 4
1 4 3
2 5 2
3 6 1
預設情況下,那些列會從DataFrame中移除,但也可以將其保留下來:
frame.set_index(['c','d'], drop=False)
a b c d
c d
one 0 0 7 one 0
1 1 6 one 1
2 2 5 one 2
two 0 3 4 two 0
1 4 3 two 1
2 5 2 two 2
3 6 1 two 3
[沒有reduce的分組參考group部分]
索引的級別會被轉移到列reset_index
reset_index的功能跟set_index剛好相反,層次化索引的級別會被轉移到列裡面:frame2.reset_index()
c d a b
0 one 0 0 7
1 one 1 1 6
2 one 2 2 5
3 two 0 3 4
4 two 1 4 3
5 two 2 5 2
6 two 3 6 1
[MultiIndex / Advanced Indexing]
顯式拷貝
索引DataFrame時返回的列是底層資料的一個視窗,而不是一個拷貝。因此,任何在Series上的就地修改都會影響DataFrame。列可以使用Series的copy 函式來顯示拷貝。 Note:While standard Python / Numpy expressions for selecting and setting are intuitive and come in handy for interactive work, for production code, were commend the optimized pandas data access methods,.at,.iat,.loc,.ilocand.ix.SettingWithCopyWarning提示
SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFramedf[len(df.columns) - 1][df[len(df.columns) - 1] > 0.0] = 1.0
這個warning主要是第二個索引導致的,就是說第二個索引是copy的。
奇怪的是,df的確已經修改了,而warnning提示好像是說修改被修改到df的一個copy上了。所以這裡只是一個warnning,只是說和記憶體有關,可能賦值不上,也可能上了。
且print(df[len(df.columns) - 1][df[len(df.columns) - 1] > 0.0].is_copy)輸出None,怎麼就輸出None,而不是True或者False?
解決
修改df原本資料時建議使用loc,但是要注意行列的索引位置Try using .loc[row_indexer,col_indexer] = value instead
df.loc[df[len(df.columns) - 1] > 0.0, len(df.columns) - 1] = 1.0不建議設定不提示:pd.options.mode.chained_assignment = None # default='warn'
參考前面why .ix is a bad idea部分
[為什麼有這種warnning的官方解釋:Returning a view versus a copy¶]
[Pandas SettingWithCopyWarning]
[How to deal with SettingWithCopyWarning in Pandas?]
Why .ix is a bad idea
通過.ix選擇的資料是一個copy的資料,修改這個選擇不會修改原資料,而.loc是修改原資料。
The .ix object tries to do more than one thing, and for anyone who has read anything about clean code, this is a strong smell.
Given this dataframe:
df = pd.DataFrame({"a": [1,2,3,4], "b": [1,1,2,2]})
Two behaviors:
dfcopy = df.ix[:,["a"]] dfcopy.a.ix[0] = 2
Behavior one: dfcopy is now a stand alone dataframe. Changing it will not change df
df.ix[0, "a"] = 3
Behavior two: This changes the original dataframe.
Use .loc instead
The pandas developers recognized that the .ix object was quite smelly[speculatively] and thus created two new objects which helps in the accession and assignment of data.
.loc is faster, because it does not try to create a copy of the data.
.loc is meant to modify your existing dataframe inplace, which is more memory efficient.
.loc is predictable, it has one behavior.
帶有重複值的軸索引
帶有重複索引值的Series
>>>obj = Series(range(5), index=['a','a','b','b','c'])
>>>obj
a 0
a 1
b 2
b 3
c 4
索引的is_unique屬性
驗證是否是唯一的
>>>obj.index.is_unique
False
帶有重複值索引的資料選取
如果某個索引對應多個值,則 返回一個Series;而對應單個值的,則返回一個標量值。>>>obj['a']
a 0
a 1
>>>obj['c']
4
對DataFrame的行進行索引時也是如此:
>>> df = DataFrame(np.random.randn(4, 3), index=['a','a','b','b'])
>>>df
>>> df.ix['b']
層次化索引
層次化索引(hierarchical indexing)是pandas的一項重要功能,它能在一個軸上擁有多個(兩個以上)索引級別。抽象點說,它使能以低維度形式處理高維度資料。Series
建立一個Series,並用一個由列表或陣列組成的列表作為索引
data = pd.Series(np.random.randn(10), index=[['a','a','a','b','b','b','c','c','d','d'], [1, 2, 3, 1, 2, 3, 1, 2, 2, 3]])In [6]: data
a 1 0.382928
2 -0.360273
3 -0.533257
b 1 0.341118
2 0.439390
3 0.645848
c 1 0.006016
2 0.700268
d 2 0.405497
3 0.188755
dtype: float64
這就是帶有Multilndex索引的Series的格式化輸出形式。索引之間的“間隔”表示“直 接使用上面的標籤”。
>>> data.index
MultiIndex(levels=[[u'a', u'b', u'c', u'd'], [1, 2, 3]], labels=[[0, 0, 0, 1, 1, 1, 2, 2, 3, 3], [0, 1, 2, 0, 1, 2, 0, 1, 1, 2]])
層次化索引的物件選取資料子集
In [8]: data['b':'c']b 1 0.341118
2 0.439390
3 0.645848
c 1 0.006016
2 0.700268
dtype: float64
In [10]: data.ix[['b', 'd']]
b 1 0.341118
2 0.439390
3 0.645848
d 2 0.405497
3 0.188755
dtype: float64
內層”中進行選取
In [11]: data[:, 2]
a -0.360273
b 0.439390
c 0.700268
d 0.405497
dtype: float64
層次化索引在資料重塑和基於分組的操作:堆疊和反堆疊
(如透視表生成)中扮演著重要的角色可通過其unstack方法被重新安排到一個DataFrame中:
In [12]: data.unstack()
1 2 3
a 0.382928 -0.360273 -0.533257
b 0.341118 0.439390 0.645848
c 0.006016 0.700268 NaN
d NaN 0.405497 0.188755
#unstack的逆運覽是stack:data.unstack().stack()
DataFrame
對於一個DataFrame,每條軸都可以有分層索引:frame = pd.DataFrame(np.arange(12).reshape((4, 3)),index=[['a','a','b','b'], [1, 2, 1, 2]],columns=[['Ohio','Ohio','Colorado'],
['Green','Red','Green']])
In [16]: frame
Ohio Colorado
Green Red Green
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11
各層都可以有名字index.name
(可以是字串,也可以是別的Python物件)。如果指定了名稱,它 們就會顯示在控制檯輸出中(不要將索引名稱跟軸標籤混為一談!):In [18]: frame.index.names = ['key1','key2']
In [19]: frame.columns.names = ['state', 'color']
In [20]: frame
state Ohio Colorado
color Green Red Green
key1 key2
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11
分部的列索引選取列分組
In [21]: frame['Ohio']color Green Red
key1 key2
a 1 0 1
2 3 4
b 1 6 7
2 9 10
單獨建立Multilndex複用
pd.MultiIndex.from_arrays([['Ohio', 'Ohio', 'Colorado'],['Green','Red', 'Green']],names=['state', 'color'])重排分級順序swaplevel和sortlevel
如需要重新調整某條軸上各級別的順序,或根據指定級別上的值對資料進行排序。調整某條軸上各級別的順序swaplevel
swaplevel接受兩個級別編號或名稱,並返回一個互換了級別的新物件(但資料不會發生變化):In [24]: frame
state Ohio Colorado
color Green Red Green
key1 key2
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11
In [25]: frame.swaplevel('key1','key2')
state Ohio Colorado
color Green Red Green
key2 key1
1 a 0 1 2
2 a 3 4 5
1 b 6 7 8
2 b 9 10 11
Note: 同frame.swaplevel(0,1)?
指定級別上的值對資料進行排序sortlevel
而sortlevel則根據單個級別中的值對資料進行排序(穩定的)。交換級別時,常常也會 用到sortlevel,這樣最終結果就是有序的了:In [26]: frame.sortlevel(1)
state Ohio Colorado
color Green Red Green
key1 key2
a 1 0 1 2
b 1 6 7 8
a 2 3 4 5
b 2 9 10 11
In [27]: frame.swaplevel(0,1).sortlevel(0)
state Ohio Colorado
color Green Red Green
key2 key1
1 a 0 1 2
b 6 7 8
2 a 3 4 5
b 9 10 11
Note:在層次化索引的物件上,如果索引是按字典方式從外到內排序(即呼叫sortlevel(0)或 sort_index()的結果),資料選取操作的效能要好很多。
根據級別彙總統計
許多對DataFrame和Series的描述和彙總統計都有一個level選項,它用於指定在某條軸上求和的級別,根據行或列上的級別來進行求和In [29]: frame
state Ohio Colorado
color Green Red Green
key1 key2
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11
In [30]: frame.sum(level='key2')
state Ohio Colorado
color Green Red Green
key2
1 6 8 10
2 12 14 16
In [33]: frame.sum(level='color',axis=1)
color Green Red
key1 key2
a 1 2 1
2 8 4
b 1 14 7
2 20 10
In [35]: frame.sum(level='color')
...
AssertionError: Level color not in index
ref: [Indexing and Selecting Data¶]*