重置索引與更換標(biāo)簽
reindex()
是 pandas 里實現(xiàn)數(shù)據(jù)對齊的基本方法精钮,該方法執(zhí)行幾乎所有功能都要用到的標(biāo)簽對齊功能。 reindex
指的是沿著指定軸,讓數(shù)據(jù)與給定的一組標(biāo)簽進行匹配蜜猾。該功能完成以下幾項操作:
- 讓現(xiàn)有數(shù)據(jù)匹配一組新標(biāo)簽今膊,并重新排序;
- 在無數(shù)據(jù)但有標(biāo)簽的位置插入缺失值(
NA
)標(biāo)記; - 如果指定扎附,則按邏輯填充無標(biāo)簽的數(shù)據(jù)抠忘,該操作多見于時間序列數(shù)據(jù)撩炊。
示例如下:
In [196]: s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
In [197]: s
Out[197]:
a 1.695148
b 1.328614
c 1.234686
d -0.385845
e -1.326508
dtype: float64
In [198]: s.reindex(['e', 'b', 'f', 'd'])
Out[198]:
e -1.326508
b 1.328614
f NaN
d -0.385845
dtype: float64
本例中,原 Series 里沒有標(biāo)簽 f
崎脉,因此衰抑,輸出結(jié)果里 f
對應(yīng)的值為 NaN
。
DataFrame 支持同時 reindex
索引與列:
In [199]: df
Out[199]:
one two three
a 1.394981 1.772517 NaN
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
d NaN 0.279344 -0.613172
In [200]: df.reindex(index=['c', 'f', 'b'], columns=['three', 'two', 'one'])
Out[200]:
three two one
c 1.227435 1.478369 0.695246
f NaN NaN NaN
b -0.050390 1.912123 0.343054
reindex
還支持 axis
關(guān)鍵字:
In [201]: df.reindex(['c', 'f', 'b'], axis='index')
Out[201]:
one two three
c 0.695246 1.478369 1.227435
f NaN NaN NaN
b 0.343054 1.912123 -0.050390
注意:不同對象可以共享 Index
包含的軸標(biāo)簽荧嵌。比如呛踊,有一個 Series砾淌,還有一個 DataFrame,可以執(zhí)行下列操作:
In [202]: rs = s.reindex(df.index)
In [203]: rs
Out[203]:
a 1.695148
b 1.328614
c 1.234686
d -0.385845
dtype: float64
In [204]: rs.index is df.index
Out[204]: True
這里指的是谭网,重置后汪厨,Series 的索引與 DataFrame 的索引是同一個 Python 對象。
0.21.0 版新增愉择。
DataFrame.reindex()
還支持 “軸樣式”調(diào)用習(xí)語劫乱,可以指定單個 labels
參數(shù),并指定應(yīng)用于哪個 axis
锥涕。
In [205]: df.reindex(['c', 'f', 'b'], axis='index')
Out[205]:
one two three
c 0.695246 1.478369 1.227435
f NaN NaN NaN
b 0.343054 1.912123 -0.050390
In [206]: df.reindex(['three', 'two', 'one'], axis='columns')
Out[206]:
three two one
a NaN 1.772517 1.394981
b -0.050390 1.912123 0.343054
c 1.227435 1.478369 0.695246
d -0.613172 0.279344 NaN
::: tip 注意
多重索引與高級索引介紹了怎樣用更簡潔的方式重置索引衷戈。
:::
::: tip 注意
編寫注重性能的代碼時,最好花些時間深入理解 reindex
:預(yù)對齊數(shù)據(jù)后层坠,操作會更快殖妇。兩個未對齊的 DataFrame 相加,后臺操作會執(zhí)行 reindex
破花。探索性分析時很難注意到這點有什么不同谦趣,這是因為 reindex
已經(jīng)進行了高度優(yōu)化,但需要注重 CPU 周期時座每,顯式調(diào)用 reindex
還是有一些影響的前鹅。
:::
重置索引,并與其它對象對齊
提取一個對象峭梳,并用另一個具有相同標(biāo)簽的對象 reindex
該對象的軸舰绘。這種操作的語法雖然簡單,但未免有些啰嗦葱椭。這時除盏,最好用 reindex_like()
方法,這是一種既有效挫以,又簡單的方式:
In [207]: df2
Out[207]:
one two
a 1.394981 1.772517
b 0.343054 1.912123
c 0.695246 1.478369
In [208]: df3
Out[208]:
one two
a 0.583888 0.051514
b -0.468040 0.191120
c -0.115848 -0.242634
In [209]: df.reindex_like(df2)
Out[209]:
one two
a 1.394981 1.772517
b 0.343054 1.912123
c 0.695246 1.478369
用 align
對齊多個對象
align()
方法是對齊兩個對象最快的方式者蠕,該方法支持 join
參數(shù)(請參閱 joining 與 merging):
-
join='outer'
:使用兩個對象索引的合集,默認(rèn)值 -
join='left'
:使用左側(cè)調(diào)用對象的索引 -
join='right'
:使用右側(cè)傳遞對象的索引 -
join='inner'
:使用兩個對象索引的交集
該方法返回重置索引后的兩個 Series 元組:
In [210]: s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
In [211]: s1 = s[:4]
In [212]: s2 = s[1:]
In [213]: s1.align(s2)
Out[213]:
(a -0.186646
b -1.692424
c -0.303893
d -1.425662
e NaN
dtype: float64, a NaN
b -1.692424
c -0.303893
d -1.425662
e 1.114285
dtype: float64)
In [214]: s1.align(s2, join='inner')
Out[214]:
(b -1.692424
c -0.303893
d -1.425662
dtype: float64, b -1.692424
c -0.303893
d -1.425662
dtype: float64)
In [215]: s1.align(s2, join='left')
Out[215]:
(a -0.186646
b -1.692424
c -0.303893
d -1.425662
dtype: float64, a NaN
b -1.692424
c -0.303893
d -1.425662
dtype: float64)
默認(rèn)條件下掐松, join
方法既應(yīng)用于索引踱侣,也應(yīng)用于列:
In [216]: df.align(df2, join='inner')
Out[216]:
( one two
a 1.394981 1.772517
b 0.343054 1.912123
c 0.695246 1.478369, one two
a 1.394981 1.772517
b 0.343054 1.912123
c 0.695246 1.478369)
align
方法還支持 axis
選項,用來指定要對齊的軸:
In [217]: df.align(df2, join='inner', axis=0)
Out[217]:
( one two three
a 1.394981 1.772517 NaN
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435, one two
a 1.394981 1.772517
b 0.343054 1.912123
c 0.695246 1.478369)
如果把 Series 傳遞給 DataFrame.align()
大磺,可以用 axis
參數(shù)選擇是在 DataFrame 的索引抡句,還是列上對齊兩個對象:
In [218]: df.align(df2.iloc[0], axis=1)
Out[218]:
( one three two
a 1.394981 NaN 1.772517
b 0.343054 -0.050390 1.912123
c 0.695246 1.227435 1.478369
d NaN -0.613172 0.279344, one 1.394981
three NaN
two 1.772517
Name: a, dtype: float64)
方法 | 動作 |
---|---|
pad / ffill | 先前填充 |
bfill / backfill | 向后填充 |
nearest | 從最近的索引值填充 |
下面用一個簡單的 Series 展示 fill
方法:
In [219]: rng = pd.date_range('1/3/2000', periods=8)
In [220]: ts = pd.Series(np.random.randn(8), index=rng)
In [221]: ts2 = ts[[0, 3, 6]]
In [222]: ts
Out[222]:
2000-01-03 0.183051
2000-01-04 0.400528
2000-01-05 -0.015083
2000-01-06 2.395489
2000-01-07 1.414806
2000-01-08 0.118428
2000-01-09 0.733639
2000-01-10 -0.936077
Freq: D, dtype: float64
In [223]: ts2
Out[223]:
2000-01-03 0.183051
2000-01-06 2.395489
2000-01-09 0.733639
dtype: float64
In [224]: ts2.reindex(ts.index)
Out[224]:
2000-01-03 0.183051
2000-01-04 NaN
2000-01-05 NaN
2000-01-06 2.395489
2000-01-07 NaN
2000-01-08 NaN
2000-01-09 0.733639
2000-01-10 NaN
Freq: D, dtype: float64
In [225]: ts2.reindex(ts.index, method='ffill')
Out[225]:
2000-01-03 0.183051
2000-01-04 0.183051
2000-01-05 0.183051
2000-01-06 2.395489
2000-01-07 2.395489
2000-01-08 2.395489
2000-01-09 0.733639
2000-01-10 0.733639
Freq: D, dtype: float64
In [226]: ts2.reindex(ts.index, method='bfill')
Out[226]:
2000-01-03 0.183051
2000-01-04 2.395489
2000-01-05 2.395489
2000-01-06 2.395489
2000-01-07 0.733639
2000-01-08 0.733639
2000-01-09 0.733639
2000-01-10 NaN
Freq: D, dtype: float64
In [227]: ts2.reindex(ts.index, method='nearest')
Out[227]:
2000-01-03 0.183051
2000-01-04 0.183051
2000-01-05 2.395489
2000-01-06 2.395489
2000-01-07 2.395489
2000-01-08 0.733639
2000-01-09 0.733639
2000-01-10 0.733639
Freq: D, dtype: float64
上述操作要求索引按遞增或遞減排序。
注意:除了 method='nearest'
杠愧,用 fillna
或 interpolate
也能實現(xiàn)同樣的效果:
In [228]: ts2.reindex(ts.index).fillna(method='ffill')
Out[228]:
2000-01-03 0.183051
2000-01-04 0.183051
2000-01-05 0.183051
2000-01-06 2.395489
2000-01-07 2.395489
2000-01-08 2.395489
2000-01-09 0.733639
2000-01-10 0.733639
Freq: D, dtype: float64
如果索引不是按遞增或遞減排序待榔,reindex()
會觸發(fā) ValueError 錯誤。fillna()
與 interpolate()
則不檢查索引的排序。
重置索引填充的限制
limit
與 tolerance
參數(shù)可以控制 reindex
的填充操作锐锣。limit
限定了連續(xù)匹配的最大數(shù)量:
In [229]: ts2.reindex(ts.index, method='ffill', limit=1)
Out[229]:
2000-01-03 0.183051
2000-01-04 0.183051
2000-01-05 NaN
2000-01-06 2.395489
2000-01-07 2.395489
2000-01-08 NaN
2000-01-09 0.733639
2000-01-10 0.733639
Freq: D, dtype: float64
反之腌闯,tolerance
限定了索引與索引器值之間的最大距離:
In [230]: ts2.reindex(ts.index, method='ffill', tolerance='1 day')
Out[230]:
2000-01-03 0.183051
2000-01-04 0.183051
2000-01-05 NaN
2000-01-06 2.395489
2000-01-07 2.395489
2000-01-08 NaN
2000-01-09 0.733639
2000-01-10 0.733639
Freq: D, dtype: float64
注意:索引為 DatetimeIndex
、TimedeltaIndex
或 PeriodIndex
時雕憔,tolerance
會盡可能將這些索引強制轉(zhuǎn)換為 Timedelta
姿骏,這里要求用戶用恰當(dāng)?shù)淖址O(shè)定 tolerance
參數(shù)。
去掉軸上的標(biāo)簽
drop()
函數(shù)與 reindex
經(jīng)常配合使用斤彼,該函數(shù)用于刪除軸上的一組標(biāo)簽:
In [231]: df
Out[231]:
one two three
a 1.394981 1.772517 NaN
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
d NaN 0.279344 -0.613172
In [232]: df.drop(['a', 'd'], axis=0)
Out[232]:
one two three
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
In [233]: df.drop(['one'], axis=1)
Out[233]:
two three
a 1.772517 NaN
b 1.912123 -0.050390
c 1.478369 1.227435
d 0.279344 -0.613172
注意:下面的代碼可以運行分瘦,但不夠清晰:
In [234]: df.reindex(df.index.difference(['a', 'd']))
Out[234]:
one two three
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
重命名或映射標(biāo)簽
rename()
方法支持按不同的軸基于映射(字典或 Series)調(diào)整標(biāo)簽。
In [235]: s
Out[235]:
a -0.186646
b -1.692424
c -0.303893
d -1.425662
e 1.114285
dtype: float64
In [236]: s.rename(str.upper)
Out[236]:
A -0.186646
B -1.692424
C -0.303893
D -1.425662
E 1.114285
dtype: float64
如果調(diào)用的是函數(shù)琉苇,該函數(shù)在處理標(biāo)簽時嘲玫,必須返回一個值,而且生成的必須是一組唯一值并扇。此外去团,rename()
還可以調(diào)用字典或 Series。
In [237]: df.rename(columns={'one': 'foo', 'two': 'bar'},
.....: index={'a': 'apple', 'b': 'banana', 'd': 'durian'})
.....:
Out[237]:
foo bar three
apple 1.394981 1.772517 NaN
banana 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
durian NaN 0.279344 -0.613172
pandas 不會重命名標(biāo)簽未包含在映射里的列或索引拜马。注意渗勘,映射里多出的標(biāo)簽不會觸發(fā)錯誤沐绒。
0.21.0 版新增俩莽。
DataFrame.rename()
還支持“軸式”習(xí)語,用這種方式可以指定單個 mapper
乔遮,及執(zhí)行映射的 axis
扮超。
In [238]: df.rename({'one': 'foo', 'two': 'bar'}, axis='columns')
Out[238]:
foo bar three
a 1.394981 1.772517 NaN
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
d NaN 0.279344 -0.613172
In [239]: df.rename({'a': 'apple', 'b': 'banana', 'd': 'durian'}, axis='index')
Out[239]:
one two three
apple 1.394981 1.772517 NaN
banana 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
durian NaN 0.279344 -0.613172
rename()
方法還提供了 inplace
命名參數(shù),默認(rèn)為 False
蹋肮,并會復(fù)制底層數(shù)據(jù)出刷。inplace=True
時,會直接在原數(shù)據(jù)上重命名坯辩。
0.18.0 版新增馁龟。
rename()
還支持用標(biāo)量或列表更改 Series.name
屬性。
In [240]: s.rename("scalar-name")
Out[240]:
a -0.186646
b -1.692424
c -0.303893
d -1.425662
e 1.114285
Name: scalar-name, dtype: float64
0.24.0 版新增漆魔。
rename_axis()
方法支持指定 多重索引
名稱坷檩,與標(biāo)簽相對應(yīng)。
In [241]: df = pd.DataFrame({'x': [1, 2, 3, 4, 5, 6],
.....: 'y': [10, 20, 30, 40, 50, 60]},
.....: index=pd.MultiIndex.from_product([['a', 'b', 'c'], [1, 2]],
.....: names=['let', 'num']))
.....:
In [242]: df
Out[242]:
x y
let num
a 1 1 10
2 2 20
b 1 3 30
2 4 40
c 1 5 50
2 6 60
In [243]: df.rename_axis(index={'let': 'abc'})
Out[243]:
x y
abc num
a 1 1 10
2 2 20
b 1 3 30
2 4 40
c 1 5 50
2 6 60
In [244]: df.rename_axis(index=str.upper)
Out[244]:
x y
LET NUM
a 1 1 10
2 2 20
b 1 3 30
2 4 40
c 1 5 50
2 6 60
迭代
pandas 對象基于類型進行迭代操作改抡。Series 迭代時被視為數(shù)組矢炼,基礎(chǔ)迭代生成值。DataFrame 則遵循字典式習(xí)語阿纤,用對象的 key
實現(xiàn)迭代操作句灌。
簡言之,基礎(chǔ)迭代(for i in object
)生成:
- Series :值
- DataFrame:列標(biāo)簽
例如欠拾,DataFrame 迭代時輸出列名:
In [245]: df = pd.DataFrame({'col1': np.random.randn(3),
.....: 'col2': np.random.randn(3)}, index=['a', 'b', 'c'])
.....:
In [246]: for col in df:
.....: print(col)
.....:
col1
col2
Pandas 對象還支持字典式的 items()
方法胰锌,通過鍵值對迭代骗绕。
用下列方法可以迭代 DataFrame 里的行:
iterrows()
:把 DataFrame 里的行當(dāng)作 (index, Series)對進行迭代匕荸。該操作把行轉(zhuǎn)為 Series爹谭,同時改變數(shù)據(jù)類型,并對性能有影響榛搔。itertuples()
把 DataFrame 的行當(dāng)作值的命名元組進行迭代诺凡。該操作比iterrows()
快的多,建議盡量用這種方法迭代 DataFrame 的值践惑。
::: danger 警告
Pandas 對象迭代的速度較慢腹泌。大部分情況下,沒必要對行執(zhí)行迭代操作尔觉,建議用以下幾種替代方式:
- 矢量化:很多操作可以用內(nèi)置方法或 Numpy 函數(shù)凉袱,布爾索引……
- 調(diào)用的函數(shù)不能在完整的 DataFrame / Series 上運行時,最好用
apply()
侦铜,不要對值進行迭代操作专甩。請參閱函數(shù)應(yīng)用文檔。 - 如果必須對值進行迭代钉稍,請務(wù)必注意代碼的性能涤躲,建議在 cython 或 numba 環(huán)境下實現(xiàn)內(nèi)循環(huán)。參閱增強性能一節(jié)贡未,查看這種操作方法的示例种樱。
:::
::: danger 警告
永遠不要修改迭代的內(nèi)容浆竭,這種方式不能確保所有操作都能正常運作羹蚣〉诙樱基于數(shù)據(jù)類型偏竟,迭代器返回的是復(fù)制(copy)的結(jié)果诚亚,不是視圖(view)更胖,這種寫入可能不會生效守问!
下例中的賦值就不會生效:
In [247]: df = pd.DataFrame({'a': [1, 2, 3], 'b': ['a', 'b', 'c']})
In [248]: for index, row in df.iterrows():
.....: row['a'] = 10
.....:
In [249]: df
Out[249]:
a b
0 1 a
1 2 b
2 3 c
:::
項目(items)
與字典型接口類似车伞,items()
通過鍵值對進行迭代:
- Series:(Index狠怨,標(biāo)量值)對
- DataFrame:(列约啊,Series)對
示例如下:
In [250]: for label, ser in df.items():
.....: print(label)
.....: print(ser)
.....:
a
0 1
1 2
2 3
Name: a, dtype: int64
b
0 a
1 b
2 c
Name: b, dtype: object
iterrows
iterrows()
迭代 DataFrame 或 Series 里的每一行數(shù)據(jù)。這個操作返回一個迭代器取董,生成索引值及包含每行數(shù)據(jù)的 Series:
In [251]: for row_index, row in df.iterrows():
.....: print(row_index, row, sep='\n')
.....:
0
a 1
b a
Name: 0, dtype: object
1
a 2
b b
Name: 1, dtype: object
2
a 3
b c
Name: 2, dtype: object
::: tip 注意
iterrows()
返回的是 Series 里的每一行數(shù)據(jù)棍苹,該操作不會保留每行數(shù)據(jù)的數(shù)據(jù)類型,因為數(shù)據(jù)類型是通過 DataFrame 的列界定的茵汰。
示例如下:
In [252]: df_orig = pd.DataFrame([[1, 1.5]], columns=['int', 'float'])
In [253]: df_orig.dtypes
Out[253]:
int int64
float float64
dtype: object
In [254]: row = next(df_orig.iterrows())[1]
In [255]: row
Out[255]:
int 1.0
float 1.5
Name: 0, dtype: float64
row
里的值以 Series 形式返回枢里,并被轉(zhuǎn)換為浮點數(shù),原始的整數(shù)值則在列 X:
In [256]: row['int'].dtype
Out[256]: dtype('float64')
In [257]: df_orig['int'].dtype
Out[257]: dtype('int64')
要想在行迭代時保存數(shù)據(jù)類型,最好用 itertuples()
栏豺,這個函數(shù)返回值的命名元組彬碱,總的來說,該操作比 iterrows()
速度更快奥洼。
:::
下例展示了怎樣轉(zhuǎn)置 DataFrame:
In [258]: df2 = pd.DataFrame({'x': [1, 2, 3], 'y': [4, 5, 6]})
In [259]: print(df2)
x y
0 1 4
1 2 5
2 3 6
In [260]: print(df2.T)
0 1 2
x 1 2 3
y 4 5 6
In [261]: df2_t = pd.DataFrame({idx: values for idx, values in df2.iterrows()})
In [262]: print(df2_t)
0 1 2
x 1 2 3
y 4 5 6
itertuples
itertuples()
方法返回為 DataFrame 里每行數(shù)據(jù)生成命名元組的迭代器巷疼。該元組的第一個元素是行的索引值,其余的值則是行的值灵奖。
示例如下:
In [263]: for row in df.itertuples():
.....: print(row)
.....:
Pandas(Index=0, a=1, b='a')
Pandas(Index=1, a=2, b='b')
Pandas(Index=2, a=3, b='c')
該方法不會把行轉(zhuǎn)換為 Series嚼沿,只是返回命名元組里的值。itertuples()
保存值的數(shù)據(jù)類型瓷患,而且比 iterrows()
快骡尽。
::: tip 注意
包含無效 Python 識別符的列名、重復(fù)的列名及以下劃線開頭的列名擅编,會被重命名為位置名稱攀细。如果列數(shù)較大,比如大于 255 列爱态,則返回正則元組谭贪。
:::
呆鳥云:“翻譯不易,五天翻譯锦担,四處求證俭识,三番校稿,二時排版吆豹,只求一秒點贊鱼的±砼瑁”