10 分鐘上手 pandas#
這份文件是 pandas 的簡要介紹,主要針對新使用者。您可以在 食譜 中看到更複雜的範例。
通常,我們會以以下方式匯入
In [1]: import numpy as np
In [2]: import pandas as pd
pandas 中的基本資料結構#
Pandas 提供兩種類型的類別來處理資料
物件建立#
請參閱 資料結構簡介部分。
透過傳遞值清單來建立 Series
,讓 pandas 建立預設 RangeIndex
。
In [3]: s = pd.Series([1, 3, 5, np.nan, 6, 8])
In [4]: s
Out[4]:
0 1.0
1 3.0
2 5.0
3 NaN
4 6.0
5 8.0
dtype: float64
透過傳遞具有日期時間索引的 NumPy 陣列,並使用 date_range()
和標籤欄位來建立 DataFrame
In [5]: dates = pd.date_range("20130101", periods=6)
In [6]: dates
Out[6]:
DatetimeIndex(['2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04',
'2013-01-05', '2013-01-06'],
dtype='datetime64[ns]', freq='D')
In [7]: df = pd.DataFrame(np.random.randn(6, 4), index=dates, columns=list("ABCD"))
In [8]: df
Out[8]:
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-03 -0.861849 -2.104569 -0.494929 1.071804
2013-01-04 0.721555 -0.706771 -1.039575 0.271860
2013-01-05 -0.424972 0.567020 0.276232 -1.087401
2013-01-06 -0.673690 0.113648 -1.478427 0.524988
透過傳遞物件字典來建立 DataFrame
,其中鍵為欄位標籤,而值為欄位值。
In [9]: df2 = pd.DataFrame(
...: {
...: "A": 1.0,
...: "B": pd.Timestamp("20130102"),
...: "C": pd.Series(1, index=list(range(4)), dtype="float32"),
...: "D": np.array([3] * 4, dtype="int32"),
...: "E": pd.Categorical(["test", "train", "test", "train"]),
...: "F": "foo",
...: }
...: )
...:
In [10]: df2
Out[10]:
A B C D E F
0 1.0 2013-01-02 1.0 3 test foo
1 1.0 2013-01-02 1.0 3 train foo
2 1.0 2013-01-02 1.0 3 test foo
3 1.0 2013-01-02 1.0 3 train foo
In [11]: df2.dtypes
Out[11]:
A float64
B datetime64[s]
C float32
D int32
E category
F object
dtype: object
如果您使用 IPython,則欄位名稱(以及公開屬性)的 tab 補全功能會自動啟用。以下是會補全的屬性子集
In [12]: df2.<TAB> # noqa: E225, E999
df2.A df2.bool
df2.abs df2.boxplot
df2.add df2.C
df2.add_prefix df2.clip
df2.add_suffix df2.columns
df2.align df2.copy
df2.all df2.count
df2.any df2.combine
df2.append df2.D
df2.apply df2.describe
df2.applymap df2.diff
df2.B df2.duplicated
如您所見,欄位 A
、B
、C
和 D
會自動 tab 補全。 E
和 F
也在其中;其餘屬性已為簡潔起見而截斷。
檢視資料#
請參閱 基本功能區段。
使用 DataFrame.head()
和 DataFrame.tail()
分別檢視框架的頂部和底部列
In [13]: df.head()
Out[13]:
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-03 -0.861849 -2.104569 -0.494929 1.071804
2013-01-04 0.721555 -0.706771 -1.039575 0.271860
2013-01-05 -0.424972 0.567020 0.276232 -1.087401
In [14]: df.tail(3)
Out[14]:
A B C D
2013-01-04 0.721555 -0.706771 -1.039575 0.271860
2013-01-05 -0.424972 0.567020 0.276232 -1.087401
2013-01-06 -0.673690 0.113648 -1.478427 0.524988
顯示 DataFrame.index
或 DataFrame.columns
In [15]: df.index
Out[15]:
DatetimeIndex(['2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04',
'2013-01-05', '2013-01-06'],
dtype='datetime64[ns]', freq='D')
In [16]: df.columns
Out[16]: Index(['A', 'B', 'C', 'D'], dtype='object')
使用 DataFrame.to_numpy()
傳回基礎資料的 NumPy 表示形式,不含索引或欄位標籤
In [17]: df.to_numpy()
Out[17]:
array([[ 0.4691, -0.2829, -1.5091, -1.1356],
[ 1.2121, -0.1732, 0.1192, -1.0442],
[-0.8618, -2.1046, -0.4949, 1.0718],
[ 0.7216, -0.7068, -1.0396, 0.2719],
[-0.425 , 0.567 , 0.2762, -1.0874],
[-0.6737, 0.1136, -1.4784, 0.525 ]])
備註
NumPy 陣列針對整個陣列只有一個 dtype,而 pandas DataFrames 則針對每一欄只有一個 dtype。當您呼叫 DataFrame.to_numpy()
時,pandas 會找出可以容納 DataFrame 中所有 dtypes 的 NumPy dtype。如果共用資料類型是 object
,DataFrame.to_numpy()
將需要複製資料。
In [18]: df2.dtypes
Out[18]:
A float64
B datetime64[s]
C float32
D int32
E category
F object
dtype: object
In [19]: df2.to_numpy()
Out[19]:
array([[1.0, Timestamp('2013-01-02 00:00:00'), 1.0, 3, 'test', 'foo'],
[1.0, Timestamp('2013-01-02 00:00:00'), 1.0, 3, 'train', 'foo'],
[1.0, Timestamp('2013-01-02 00:00:00'), 1.0, 3, 'test', 'foo'],
[1.0, Timestamp('2013-01-02 00:00:00'), 1.0, 3, 'train', 'foo']],
dtype=object)
describe()
顯示資料的快速統計摘要
In [20]: df.describe()
Out[20]:
A B C D
count 6.000000 6.000000 6.000000 6.000000
mean 0.073711 -0.431125 -0.687758 -0.233103
std 0.843157 0.922818 0.779887 0.973118
min -0.861849 -2.104569 -1.509059 -1.135632
25% -0.611510 -0.600794 -1.368714 -1.076610
50% 0.022070 -0.228039 -0.767252 -0.386188
75% 0.658444 0.041933 -0.034326 0.461706
max 1.212112 0.567020 0.276232 1.071804
轉置資料
In [21]: df.T
Out[21]:
2013-01-01 2013-01-02 2013-01-03 2013-01-04 2013-01-05 2013-01-06
A 0.469112 1.212112 -0.861849 0.721555 -0.424972 -0.673690
B -0.282863 -0.173215 -2.104569 -0.706771 0.567020 0.113648
C -1.509059 0.119209 -0.494929 -1.039575 0.276232 -1.478427
D -1.135632 -1.044236 1.071804 0.271860 -1.087401 0.524988
DataFrame.sort_index()
依照軸排序
In [22]: df.sort_index(axis=1, ascending=False)
Out[22]:
D C B A
2013-01-01 -1.135632 -1.509059 -0.282863 0.469112
2013-01-02 -1.044236 0.119209 -0.173215 1.212112
2013-01-03 1.071804 -0.494929 -2.104569 -0.861849
2013-01-04 0.271860 -1.039575 -0.706771 0.721555
2013-01-05 -1.087401 0.276232 0.567020 -0.424972
2013-01-06 0.524988 -1.478427 0.113648 -0.673690
DataFrame.sort_values()
依照值排序
In [23]: df.sort_values(by="B")
Out[23]:
A B C D
2013-01-03 -0.861849 -2.104569 -0.494929 1.071804
2013-01-04 0.721555 -0.706771 -1.039575 0.271860
2013-01-01 0.469112 -0.282863 -1.509059 -1.135632
2013-01-02 1.212112 -0.173215 0.119209 -1.044236
2013-01-06 -0.673690 0.113648 -1.478427 0.524988
2013-01-05 -0.424972 0.567020 0.276232 -1.087401
選取#
備註
標準 Python/NumPy 選取和設定表達式雖然直觀且適合互動式工作,但對於生產程式碼,我們建議使用最佳化的 pandas 資料存取方法,DataFrame.at()
、DataFrame.iat()
、DataFrame.loc()
和 DataFrame.iloc()
。
Getitem ([]
)#
對於 DataFrame
,傳遞單一標籤會選取一欄並產生一個 Series
,等同於 df.A
In [24]: df["A"]
Out[24]:
2013-01-01 0.469112
2013-01-02 1.212112
2013-01-03 -0.861849
2013-01-04 0.721555
2013-01-05 -0.424972
2013-01-06 -0.673690
Freq: D, Name: A, dtype: float64
對於 DataFrame
,傳遞切片 :
會選取符合的列
In [25]: df[0:3]
Out[25]:
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-03 -0.861849 -2.104569 -0.494929 1.071804
In [26]: df["20130102":"20130104"]
Out[26]:
A B C D
2013-01-02 1.212112 -0.173215 0.119209 -1.044236
2013-01-03 -0.861849 -2.104569 -0.494929 1.071804
2013-01-04 0.721555 -0.706771 -1.039575 0.271860
依標籤選取#
請參閱 依標籤選取 中使用 DataFrame.loc()
或 DataFrame.at()
的更多資訊。
選取符合標籤的列
In [27]: df.loc[dates[0]]
Out[27]:
A 0.469112
B -0.282863
C -1.509059
D -1.135632
Name: 2013-01-01 00:00:00, dtype: float64
選取所有列 (:
) 搭配選取的欄標籤
In [28]: df.loc[:, ["A", "B"]]
Out[28]:
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
對於標籤切片,兩個端點都會包含
In [29]: df.loc["20130102":"20130104", ["A", "B"]]
Out[29]:
A B
2013-01-02 1.212112 -0.173215
2013-01-03 -0.861849 -2.104569
2013-01-04 0.721555 -0.706771
選取單一列和欄標籤會傳回一個純量
In [30]: df.loc[dates[0], "A"]
Out[30]: 0.4691122999071863
快速存取純量(等同於前述方法)
In [31]: df.at[dates[0], "A"]
Out[31]: 0.4691122999071863
依位置選取#
在 按位置選取 中使用 DataFrame.iloc()
或 DataFrame.iat()
查看更多資訊。
透過傳遞整數的位置來選取
In [32]: df.iloc[3]
Out[32]:
A 0.721555
B -0.706771
C -1.039575
D 0.271860
Name: 2013-01-04 00:00:00, dtype: float64
整數切片與 NumPy/Python 類似
In [33]: df.iloc[3:5, 0:2]
Out[33]:
A B
2013-01-04 0.721555 -0.706771
2013-01-05 -0.424972 0.567020
整數位置位置清單
In [34]: df.iloc[[1, 2, 4], [0, 2]]
Out[34]:
A C
2013-01-02 1.212112 0.119209
2013-01-03 -0.861849 -0.494929
2013-01-05 -0.424972 0.276232
明確切片列
In [35]: df.iloc[1:3, :]
Out[35]:
A B C D
2013-01-02 1.212112 -0.173215 0.119209 -1.044236
2013-01-03 -0.861849 -2.104569 -0.494929 1.071804
明確切片欄
In [36]: df.iloc[:, 1:3]
Out[36]:
B C
2013-01-01 -0.282863 -1.509059
2013-01-02 -0.173215 0.119209
2013-01-03 -2.104569 -0.494929
2013-01-04 -0.706771 -1.039575
2013-01-05 0.567020 0.276232
2013-01-06 0.113648 -1.478427
明確取得值
In [37]: df.iloc[1, 1]
Out[37]: -0.17321464905330858
快速存取純量(等同於前述方法)
In [38]: df.iat[1, 1]
Out[38]: -0.17321464905330858
布林索引#
選取其中 df.A
大於 0
的列。
In [39]: df[df["A"] > 0]
Out[39]:
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
從符合布林條件的 DataFrame
中選取值
In [40]: df[df > 0]
Out[40]:
A B C D
2013-01-01 0.469112 NaN NaN NaN
2013-01-02 1.212112 NaN 0.119209 NaN
2013-01-03 NaN NaN NaN 1.071804
2013-01-04 0.721555 NaN NaN 0.271860
2013-01-05 NaN 0.567020 0.276232 NaN
2013-01-06 NaN 0.113648 NaN 0.524988
使用 isin()
方法進行篩選
In [41]: df2 = df.copy()
In [42]: df2["E"] = ["one", "one", "two", "three", "four", "three"]
In [43]: df2
Out[43]:
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
設定#
設定新欄會自動依索引對齊資料
In [45]: s1 = pd.Series([1, 2, 3, 4, 5, 6], index=pd.date_range("20130102", periods=6))
In [46]: s1
Out[46]:
2013-01-02 1
2013-01-03 2
2013-01-04 3
2013-01-05 4
2013-01-06 5
2013-01-07 6
Freq: D, dtype: int64
In [47]: df["F"] = s1
依標籤設定值
In [48]: df.at[dates[0], "A"] = 0
依位置設定值
In [49]: df.iat[0, 1] = 0
透過指定 NumPy 陣列來設定
In [50]: df.loc[:, "D"] = np.array([5] * len(df))
先前設定作業的結果
In [51]: df
Out[51]:
A B C D F
2013-01-01 0.000000 0.000000 -1.509059 5.0 NaN
2013-01-02 1.212112 -0.173215 0.119209 5.0 1.0
2013-01-03 -0.861849 -2.104569 -0.494929 5.0 2.0
2013-01-04 0.721555 -0.706771 -1.039575 5.0 3.0
2013-01-05 -0.424972 0.567020 0.276232 5.0 4.0
2013-01-06 -0.673690 0.113648 -1.478427 5.0 5.0
包含設定的 where
In [52]: df2 = df.copy()
In [53]: df2[df2 > 0] = -df2
In [54]: df2
Out[54]:
A B C D F
2013-01-01 0.000000 0.000000 -1.509059 -5.0 NaN
2013-01-02 -1.212112 -0.173215 -0.119209 -5.0 -1.0
2013-01-03 -0.861849 -2.104569 -0.494929 -5.0 -2.0
2013-01-04 -0.721555 -0.706771 -1.039575 -5.0 -3.0
2013-01-05 -0.424972 -0.567020 -0.276232 -5.0 -4.0
2013-01-06 -0.673690 -0.113648 -1.478427 -5.0 -5.0
遺失的資料#
對於 NumPy 資料類型,np.nan
代表遺失的資料。它預設不包含在運算中。請參閱遺失資料區段。
重新索引可讓您變更/新增/刪除指定軸上的索引。這會傳回資料的副本
In [55]: df1 = df.reindex(index=dates[0:4], columns=list(df.columns) + ["E"])
In [56]: df1.loc[dates[0] : dates[1], "E"] = 1
In [57]: df1
Out[57]:
A B C D F E
2013-01-01 0.000000 0.000000 -1.509059 5.0 NaN 1.0
2013-01-02 1.212112 -0.173215 0.119209 5.0 1.0 1.0
2013-01-03 -0.861849 -2.104569 -0.494929 5.0 2.0 NaN
2013-01-04 0.721555 -0.706771 -1.039575 5.0 3.0 NaN
DataFrame.dropna()
會移除任何有遺失資料的列
In [58]: df1.dropna(how="any")
Out[58]:
A B C D F E
2013-01-02 1.212112 -0.173215 0.119209 5.0 1.0 1.0
DataFrame.fillna()
會填入遺失的資料
In [59]: df1.fillna(value=5)
Out[59]:
A B C D F E
2013-01-01 0.000000 0.000000 -1.509059 5.0 5.0 1.0
2013-01-02 1.212112 -0.173215 0.119209 5.0 1.0 1.0
2013-01-03 -0.861849 -2.104569 -0.494929 5.0 2.0 5.0
2013-01-04 0.721555 -0.706771 -1.039575 5.0 3.0 5.0
isna()
會取得值為nan
的布林遮罩
In [60]: pd.isna(df1)
Out[60]:
A B C D F E
2013-01-01 False False False False True False
2013-01-02 False False False False False False
2013-01-03 False False False False False True
2013-01-04 False False False False False True
運算#
請參閱二元運算基礎區段。
統計#
一般來說,運算會排除遺失的資料。
計算每列的平均值
In [61]: df.mean()
Out[61]:
A -0.004474
B -0.383981
C -0.687758
D 5.000000
F 3.000000
dtype: float64
計算每列的平均值
In [62]: df.mean(axis=1)
Out[62]:
2013-01-01 0.872735
2013-01-02 1.431621
2013-01-03 0.707731
2013-01-04 1.395042
2013-01-05 1.883656
2013-01-06 1.592306
Freq: D, dtype: float64
與另一個具有不同索引或欄位的 Series
或 DataFrame
一起操作時,會將結果與索引或欄位標籤的聯集對齊。此外,pandas 會自動沿著指定的維度廣播,並使用 np.nan
In [63]: s = pd.Series([1, 3, 5, np.nan, 6, 8], index=dates).shift(2)
In [64]: s
Out[64]:
2013-01-01 NaN
2013-01-02 NaN
2013-01-03 1.0
2013-01-04 3.0
2013-01-05 5.0
2013-01-06 NaN
Freq: D, dtype: float64
In [65]: df.sub(s, axis="index")
Out[65]:
A B C D F
2013-01-01 NaN NaN NaN NaN NaN
2013-01-02 NaN NaN NaN NaN NaN
2013-01-03 -1.861849 -3.104569 -1.494929 4.0 1.0
2013-01-04 -2.278445 -3.706771 -4.039575 2.0 0.0
2013-01-05 -5.424972 -4.432980 -4.723768 0.0 -1.0
2013-01-06 NaN NaN NaN NaN NaN
使用者自訂函數#
DataFrame.agg()
和 DataFrame.transform()
分別套用使用者自訂函數來縮減或廣播其結果。
In [66]: df.agg(lambda x: np.mean(x) * 5.6)
Out[66]:
A -0.025054
B -2.150294
C -3.851445
D 28.000000
F 16.800000
dtype: float64
In [67]: df.transform(lambda x: x * 101.2)
Out[67]:
A B C D F
2013-01-01 0.000000 0.000000 -152.716721 506.0 NaN
2013-01-02 122.665737 -17.529322 12.063922 506.0 101.2
2013-01-03 -87.219115 -212.982405 -50.086843 506.0 202.4
2013-01-04 73.021382 -71.525239 -105.204988 506.0 303.6
2013-01-05 -43.007200 57.382459 27.954680 506.0 404.8
2013-01-06 -68.177398 11.501219 -149.616767 506.0 506.0
值計數#
請參閱 直方圖和離散化 中的更多資訊。
In [68]: s = pd.Series(np.random.randint(0, 7, size=10))
In [69]: s
Out[69]:
0 4
1 2
2 1
3 2
4 6
5 4
6 4
7 6
8 4
9 4
dtype: int64
In [70]: s.value_counts()
Out[70]:
4 5
2 2
6 2
1 1
Name: count, dtype: int64
字串方法#
Series
在 str
屬性中配備一組字串處理方法,讓您能輕鬆地對陣列的每個元素進行操作,如下面的程式碼片段所示。請參閱 向量化字串方法 中的更多資訊。
In [71]: s = pd.Series(["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "dog", "cat"])
In [72]: s.str.lower()
Out[72]:
0 a
1 b
2 c
3 aaba
4 baca
5 NaN
6 caba
7 dog
8 cat
dtype: object
合併#
串接#
pandas 提供多種便利的工具,可輕鬆結合 Series
和 DataFrame
物件,並提供各種索引設定邏輯,以及在連接/合併型操作中使用的關聯代數功能。
請參閱 合併區段。
使用 concat()
將 pandas 物件以列為基礎串接在一起
In [73]: df = pd.DataFrame(np.random.randn(10, 4))
In [74]: df
Out[74]:
0 1 2 3
0 -0.548702 1.467327 -1.015962 -0.483075
1 1.637550 -1.217659 -0.291519 -1.745505
2 -0.263952 0.991460 -0.919069 0.266046
3 -0.709661 1.669052 1.037882 -1.705775
4 -0.919854 -0.042379 1.247642 -0.009920
5 0.290213 0.495767 0.362949 1.548106
6 -1.131345 -0.089329 0.337863 -0.945867
7 -0.932132 1.956030 0.017587 -0.016692
8 -0.575247 0.254161 -1.143704 0.215897
9 1.193555 -0.077118 -0.408530 -0.862495
# break it into pieces
In [75]: pieces = [df[:3], df[3:7], df[7:]]
In [76]: pd.concat(pieces)
Out[76]:
0 1 2 3
0 -0.548702 1.467327 -1.015962 -0.483075
1 1.637550 -1.217659 -0.291519 -1.745505
2 -0.263952 0.991460 -0.919069 0.266046
3 -0.709661 1.669052 1.037882 -1.705775
4 -0.919854 -0.042379 1.247642 -0.009920
5 0.290213 0.495767 0.362949 1.548106
6 -1.131345 -0.089329 0.337863 -0.945867
7 -0.932132 1.956030 0.017587 -0.016692
8 -0.575247 0.254161 -1.143704 0.215897
9 1.193555 -0.077118 -0.408530 -0.862495
連接#
merge()
啟用特定欄位之間的 SQL 風格連接類型。請參閱 資料庫風格連接 區段。
In [77]: left = pd.DataFrame({"key": ["foo", "foo"], "lval": [1, 2]})
In [78]: right = pd.DataFrame({"key": ["foo", "foo"], "rval": [4, 5]})
In [79]: left
Out[79]:
key lval
0 foo 1
1 foo 2
In [80]: right
Out[80]:
key rval
0 foo 4
1 foo 5
In [81]: pd.merge(left, right, on="key")
Out[81]:
key lval rval
0 foo 1 4
1 foo 1 5
2 foo 2 4
3 foo 2 5
merge()
針對唯一金鑰
In [82]: left = pd.DataFrame({"key": ["foo", "bar"], "lval": [1, 2]})
In [83]: right = pd.DataFrame({"key": ["foo", "bar"], "rval": [4, 5]})
In [84]: left
Out[84]:
key lval
0 foo 1
1 bar 2
In [85]: right
Out[85]:
key rval
0 foo 4
1 bar 5
In [86]: pd.merge(left, right, on="key")
Out[86]:
key lval rval
0 foo 1 4
1 bar 2 5
群組#
「群組依據」是指包含下列一個或多個步驟的程序
分割資料成依據特定條件的群組
套用函數至每個獨立的群組
結合結果成資料結構
請參閱 群組區段。
In [87]: df = pd.DataFrame(
....: {
....: "A": ["foo", "bar", "foo", "bar", "foo", "bar", "foo", "foo"],
....: "B": ["one", "one", "two", "three", "two", "two", "one", "three"],
....: "C": np.random.randn(8),
....: "D": np.random.randn(8),
....: }
....: )
....:
In [88]: df
Out[88]:
A B C D
0 foo one 1.346061 -1.577585
1 bar one 1.511763 0.396823
2 foo two 1.627081 -0.105381
3 bar three -0.990582 -0.532532
4 foo two -0.441652 1.453749
5 bar two 1.211526 1.208843
6 foo one 0.268520 -0.080952
7 foo three 0.024580 -0.264610
依據欄位標籤群組,選擇欄位標籤,然後套用 DataFrameGroupBy.sum()
函數至結果群組
In [89]: df.groupby("A")[["C", "D"]].sum()
Out[89]:
C D
A
bar 1.732707 1.073134
foo 2.824590 -0.574779
依據多個欄位標籤群組形成 MultiIndex
。
In [90]: df.groupby(["A", "B"]).sum()
Out[90]:
C D
A B
bar one 1.511763 0.396823
three -0.990582 -0.532532
two 1.211526 1.208843
foo one 1.614581 -1.658537
three 0.024580 -0.264610
two 1.185429 1.348368
變形#
堆疊#
In [91]: arrays = [
....: ["bar", "bar", "baz", "baz", "foo", "foo", "qux", "qux"],
....: ["one", "two", "one", "two", "one", "two", "one", "two"],
....: ]
....:
In [92]: index = pd.MultiIndex.from_arrays(arrays, names=["first", "second"])
In [93]: df = pd.DataFrame(np.random.randn(8, 2), index=index, columns=["A", "B"])
In [94]: df2 = df[:4]
In [95]: df2
Out[95]:
A B
first second
bar one -0.727965 -0.589346
two 0.339969 -0.693205
baz one -0.339355 0.593616
two 0.884345 1.591431
stack()
方法「壓縮」DataFrame 欄位中的層級
In [96]: stacked = df2.stack(future_stack=True)
In [97]: stacked
Out[97]:
first second
bar one A -0.727965
B -0.589346
two A 0.339969
B -0.693205
baz one A -0.339355
B 0.593616
two A 0.884345
B 1.591431
dtype: float64
對於「堆疊」的 DataFrame 或 Series(具有 MultiIndex
作為 index
),stack()
的反向操作是 unstack()
,它預設會取消堆疊最後一層
In [98]: stacked.unstack()
Out[98]:
A B
first second
bar one -0.727965 -0.589346
two 0.339969 -0.693205
baz one -0.339355 0.593616
two 0.884345 1.591431
In [99]: stacked.unstack(1)
Out[99]:
second one two
first
bar A -0.727965 0.339969
B -0.589346 -0.693205
baz A -0.339355 0.884345
B 0.593616 1.591431
In [100]: stacked.unstack(0)
Out[100]:
first bar baz
second
one A -0.727965 -0.339355
B -0.589346 0.593616
two A 0.339969 0.884345
B -0.693205 1.591431
樞紐資料表#
請參閱 樞紐資料表 部分。
In [101]: df = pd.DataFrame(
.....: {
.....: "A": ["one", "one", "two", "three"] * 3,
.....: "B": ["A", "B", "C"] * 4,
.....: "C": ["foo", "foo", "foo", "bar", "bar", "bar"] * 2,
.....: "D": np.random.randn(12),
.....: "E": np.random.randn(12),
.....: }
.....: )
.....:
In [102]: df
Out[102]:
A B C D E
0 one A foo -1.202872 0.047609
1 one B foo -1.814470 -0.136473
2 two C foo 1.018601 -0.561757
3 three A bar -0.595447 -1.623033
4 one B bar 1.395433 0.029399
5 one C bar -0.392670 -0.542108
6 two A foo 0.007207 0.282696
7 three B foo 1.928123 -0.087302
8 one C foo -0.055224 -1.575170
9 one A bar 2.395985 1.771208
10 two B bar 1.552825 0.816482
11 three C bar 0.166599 1.100230
pivot_table()
會樞紐一個 DataFrame
,並指定 values
、index
和 columns
In [103]: pd.pivot_table(df, values="D", index=["A", "B"], columns=["C"])
Out[103]:
C bar foo
A B
one A 2.395985 -1.202872
B 1.395433 -1.814470
C -0.392670 -0.055224
three A -0.595447 NaN
B NaN 1.928123
C 0.166599 NaN
two A NaN 0.007207
B 1.552825 NaN
C NaN 1.018601
時間序列#
pandas 具有簡單、強大且有效率的功能,可在頻率轉換期間執行重新取樣操作(例如,將每秒資料轉換為每 5 分鐘資料)。這在金融應用程式中極為常見,但不僅限於此。請參閱 時間序列部分。
In [104]: rng = pd.date_range("1/1/2012", periods=100, freq="s")
In [105]: ts = pd.Series(np.random.randint(0, 500, len(rng)), index=rng)
In [106]: ts.resample("5Min").sum()
Out[106]:
2012-01-01 24182
Freq: 5min, dtype: int64
Series.tz_localize()
將時間序列定位到時區
In [107]: rng = pd.date_range("3/6/2012 00:00", periods=5, freq="D")
In [108]: ts = pd.Series(np.random.randn(len(rng)), rng)
In [109]: ts
Out[109]:
2012-03-06 1.857704
2012-03-07 -1.193545
2012-03-08 0.677510
2012-03-09 -0.153931
2012-03-10 0.520091
Freq: D, dtype: float64
In [110]: ts_utc = ts.tz_localize("UTC")
In [111]: ts_utc
Out[111]:
2012-03-06 00:00:00+00:00 1.857704
2012-03-07 00:00:00+00:00 -1.193545
2012-03-08 00:00:00+00:00 0.677510
2012-03-09 00:00:00+00:00 -0.153931
2012-03-10 00:00:00+00:00 0.520091
Freq: D, dtype: float64
Series.tz_convert()
將時區感知時間序列轉換到另一個時區
In [112]: ts_utc.tz_convert("US/Eastern")
Out[112]:
2012-03-05 19:00:00-05:00 1.857704
2012-03-06 19:00:00-05:00 -1.193545
2012-03-07 19:00:00-05:00 0.677510
2012-03-08 19:00:00-05:00 -0.153931
2012-03-09 19:00:00-05:00 0.520091
Freq: D, dtype: float64
將非固定持續時間 (BusinessDay
) 新增到時間序列
In [113]: rng
Out[113]:
DatetimeIndex(['2012-03-06', '2012-03-07', '2012-03-08', '2012-03-09',
'2012-03-10'],
dtype='datetime64[ns]', freq='D')
In [114]: rng + pd.offsets.BusinessDay(5)
Out[114]:
DatetimeIndex(['2012-03-13', '2012-03-14', '2012-03-15', '2012-03-16',
'2012-03-16'],
dtype='datetime64[ns]', freq=None)
分類#
pandas 可以將分類資料包含在 DataFrame
中。有關完整文件,請參閱 分類簡介 和 API 文件。
In [115]: df = pd.DataFrame(
.....: {"id": [1, 2, 3, 4, 5, 6], "raw_grade": ["a", "b", "b", "a", "a", "e"]}
.....: )
.....:
將原始成績轉換為分類資料類型
In [116]: df["grade"] = df["raw_grade"].astype("category")
In [117]: df["grade"]
Out[117]:
0 a
1 b
2 b
3 a
4 a
5 e
Name: grade, dtype: category
Categories (3, object): ['a', 'b', 'e']
將類別重新命名為更有意義的名稱
In [118]: new_categories = ["very good", "good", "very bad"]
In [119]: df["grade"] = df["grade"].cat.rename_categories(new_categories)
重新排序類別並同時新增遺失的類別(Series.cat()
下的方法預設會傳回新的 Series
)
In [120]: df["grade"] = df["grade"].cat.set_categories(
.....: ["very bad", "bad", "medium", "good", "very good"]
.....: )
.....:
In [121]: df["grade"]
Out[121]:
0 very good
1 good
2 good
3 very good
4 very good
5 very bad
Name: grade, dtype: category
Categories (5, object): ['very bad', 'bad', 'medium', 'good', 'very good']
排序依類別順序,而非字彙順序
In [122]: df.sort_values(by="grade")
Out[122]:
id raw_grade grade
5 6 e very bad
1 2 b good
2 3 b good
0 1 a very good
3 4 a very good
4 5 a very good
依類別欄位分組,且 observed=False
也會顯示空類別
In [123]: df.groupby("grade", observed=False).size()
Out[123]:
grade
very bad 1
bad 0
medium 0
good 2
very good 3
dtype: int64
繪圖#
請參閱 繪圖 文件。
我們使用標準慣例來參照 matplotlib API
In [124]: import matplotlib.pyplot as plt
In [125]: plt.close("all")
plt.close
方法用於 關閉 圖形視窗
In [126]: ts = pd.Series(np.random.randn(1000), index=pd.date_range("1/1/2000", periods=1000))
In [127]: ts = ts.cumsum()
In [128]: ts.plot();

備註
在使用 Jupyter 時,會使用 plot()
顯示圖形。否則,請使用 matplotlib.pyplot.show 顯示圖形,或使用 matplotlib.pyplot.savefig 將圖形寫入檔案。
plot()
會繪製所有欄位
In [129]: df = pd.DataFrame(
.....: np.random.randn(1000, 4), index=ts.index, columns=["A", "B", "C", "D"]
.....: )
.....:
In [130]: df = df.cumsum()
In [131]: plt.figure();
In [132]: df.plot();
In [133]: plt.legend(loc='best');

匯入和匯出資料#
請參閱 IO 工具 區段。
CSV#
寫入 csv 檔案:使用 DataFrame.to_csv()
In [134]: df = pd.DataFrame(np.random.randint(0, 5, (10, 5)))
In [135]: df.to_csv("foo.csv")
In [136]: pd.read_csv("foo.csv")
Out[136]:
Unnamed: 0 0 1 2 3 4
0 0 4 3 1 1 2
1 1 1 0 2 3 2
2 2 1 4 2 1 2
3 3 0 4 0 2 2
4 4 4 2 2 3 4
5 5 4 0 4 3 1
6 6 2 1 2 0 3
7 7 4 0 4 4 4
8 8 4 4 1 0 1
9 9 0 4 3 0 3
Parquet#
寫入 Parquet 檔案
In [137]: df.to_parquet("foo.parquet")
從 Parquet 檔案讀取使用 read_parquet()
儲存
In [138]: pd.read_parquet("foo.parquet")
Out[138]:
0 1 2 3 4
0 4 3 1 1 2
1 1 0 2 3 2
2 1 4 2 1 2
3 0 4 0 2 2
4 4 2 2 3 4
5 4 0 4 3 1
6 2 1 2 0 3
7 4 0 4 4 4
8 4 4 1 0 1
9 0 4 3 0 3
Excel#
讀取和寫入 Excel。
使用 DataFrame.to_excel()
寫入 Excel 檔案
In [139]: df.to_excel("foo.xlsx", sheet_name="Sheet1")
使用 read_excel()
從 Excel 檔案讀取
In [140]: pd.read_excel("foo.xlsx", "Sheet1", index_col=None, na_values=["NA"])
Out[140]:
Unnamed: 0 0 1 2 3 4
0 0 4 3 1 1 2
1 1 1 0 2 3 2
2 2 1 4 2 1 2
3 3 0 4 0 2 2
4 4 4 2 2 3 4
5 5 4 0 4 3 1
6 6 2 1 2 0 3
7 7 4 0 4 4 4
8 8 4 4 1 0 1
9 9 0 4 3 0 3
陷阱#
如果您嘗試對 Series
或 DataFrame
執行布林運算,您可能會看到類似這樣的例外
In [141]: if pd.Series([False, True, False]):
.....: print("I was true")
.....:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-141-b27eb9c1dfc0> in ?()
----> 1 if pd.Series([False, True, False]):
2 print("I was true")
~/work/pandas/pandas/pandas/core/generic.py in ?(self)
1574 @final
1575 def __nonzero__(self) -> NoReturn:
-> 1576 raise ValueError(
1577 f"The truth value of a {type(self).__name__} is ambiguous. "
1578 "Use a.empty, a.bool(), a.item(), a.any() or a.all()."
1579 )
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().