[ Pandas version: 1.0.1 ]
import pandas as pd
一、Pandas對象
Pandas的三個基本數據結構:Series, DataFrame, Index
(一) Pandas的Series對象
Pandas的Series對象是一個帶索引數據構成的一維數組。
通過values
屬性和index
屬性獲取數據。values屬性返回的結果與NumPy數組類似。
data = pd.Series([0.25, 0.5, 0.75, 1.0])
#0 0.25
#1 0.50
#2 0.75
#3 1.00
#dtype: float64
data.values #輸出:array([0.25, 0.5 , 0.75, 1. ])
data.index #輸出:RangeIndex(start=0, stop=4, step=1)
data[1]
data[1:3]
#1 0.50
#2 0.75
#dtype: float64
- Series是通用的NumPy數組
NumPy數組通過隱式定義的整數索引獲取數值。
Pandas的Series對象通過顯式定義的索引與數值關聯,其索引可以是任意類型,可使用不連續或不按順序的索引。
data = pd.Series([0.25, 0.5, 0.75, 1.0], index=['a', 'b', 'c', 'd'])
data = pd.Series([0.25, 0.5, 0.75, 1.0], index=[2, 5, 3, 7])
- Series是特殊的字典
Python字典是一種將任意鍵映射到一組任意值的數據結構。
Series對象是一直將類型鍵映射到一組類型值的數據結構,支持字典不具有的功能,如切片。
population_dict = {'California': 38332521, 'Texas': 26448193, 'New York': 19651127}
population = pd.Series(population_dict)
# California 38332521
# Texas 26448193
# New York 19651127
# dtype: int64
population['California']
# 切片
population['California':'Texas']
- 創建Series對象:
pd.Series(data, index=index)
- 其中
index
是可選參數,data
參數支持多種數據類型。 - Series對象只會保留顯式定義的鍵值對。
- 每種形式都可以通過顯示指定索引篩選需要的結果
# 1. data是列表或NumPy數組,這時index默認值爲整數序列
pd.Series([2, 4, 6])
# 2. data是標量,創建Series對象時會重複填充到每個索引上
pd.Series(5, index=[100, 200, 300])
# 3. data是字典,index默認是排序的字典鍵
pd.Series({2:'a', 1:'b', 3:'c'})
# 每種形式都可以通過顯示指定索引篩選需要的結果
pd.Series({2:'a', 1:'b', 3:'c'}, index=[3, 2])
#3 c
#2 a
#dtype: object
(二) Pandas的DataFrame對象
- DataFrame是通用的NumPy數組
DataFrame可以看做是一種有行和列索引的二維數組,也可看作是有序排列(有共同索引)的若干Series對象。
area_dict = {'California': 423967, 'Texas': 695662, 'New York': 141297}
area = pd.Series(area_dict)
states = pd.DataFrame({'population': population, 'area': area})
states
# population area
# California 38332521 423967
# Texas 26448193 695662
# New York 19651127 141297
DataFrame屬性:index
、columns
# DataFrame有index屬性獲取索引標籤
states.index #輸出:Index(['California', 'Texas', 'New York'], dtype='object')
# DataFrame有columns屬性存放列標籤的index對象
states.columns #輸出:Index(['population', 'area'], dtype='object')
- DataFrame是特殊的字典:一列映射一個Series的數據
states['area']
# California 423967
# Texas 695662
# New York 141297
# Name: area, dtype: int64
- 創建DataFrame對象:
pd.DataFrame(data, columns=columns, index=index)
# 1. 通過單個Series對象創建
pd.DataFrame(population, columns=['population'])
# population
# California 38332521
# Texas 26448193
# New York 19651127
# 2. 通過字典列表創建
data = [{'a': i, 'b': 2 * i} for i in range(3)] #data: [{'a': 0, 'b': 0}, {'a': 1, 'b': 2}, {'a': 2, 'b': 4}]
pd.DataFrame(data)
# a b
# 0 0 0
# 1 1 2
# 2 2 4
# 即使字典中有些鍵不存在,Pandas也會用缺失值NaN表示
pd.DataFrame([{'a': 1, 'b': 2}, {'b': 3, 'c': 4}])
# a b c
# 0 1.0 2 NaN
# 1 NaN 3 4.0
# 3. 通過Series對象字典創建
pd.DataFrame({'population': population, 'area': area})
# 4. 通過NumPy二維數組創建
pd.DataFrame(np.random.rand(3, 2), columns=['foo', 'bar'], index=['a', 'b', 'c'])
# foo bar
# a 0.428555 0.416076
# b 0.368652 0.115681
# c 0.381276 0.704019
# 注:如果不指定行列索引值,那麼行列默認都是整數索引值
pd.DataFrame(np.random.rand(3, 2)
# 0 1
# 0 0.973628 0.960743
# 1 0.312451 0.824474
# 2 0.956125 0.275362
# 5. 通過NumPy結構化數組創建
A = np.zeros(3, dtype=[('A', 'i8'), ('B', 'f8')])
A #輸出:array([(0, 0.), (0, 0.), (0, 0.)], dtype=[('A', '<i8'), ('B', '<f8')])
pd.DataFrame(A)
# A B
# 0 0 0.0
# 1 0 0.0
# 2 0 0.0
(三) Pandas的Index對象
- 將Index看作不可變數組
Index對象的索引是不可變的,這個不可變特性使得多個DataFrame和數組之間進行索引共享時更加安全,尤其是可以避免因修改索引時粗心導致的副作用。
ind = pd.Index([2, 3, 5, 7, 11])
ind #輸出:Int64Index([2, 3, 5, 7, 11], dtype='int64')
ind[1] #輸出:3
ind[::2] #輸出:Int64Index([2, 5, 11], dtype='int64')
print(ind.size, ind.shape, ind.ndim, ind.dtype)
# 5 (5,) 1 int64
#ind[1] = 0 -> TypeError 不可賦值
- 將Index看作有序集合(實際上是一個多集:Index對象可以包含重複值)
Pandas對象涉及許多集合操作,遵循Python集合的許多習慣用法,包括並集、交集、差集等。
indA = pd.Index([1, 3, 5, 7, 9])
indB = pd.Index([2, 3, 5, 7, 11])
indA & indB #交集,輸出:Int64Index([3, 5, 7], dtype='int64')
indA | indB #並集,輸出:Int64Index([1, 2, 3, 5, 7, 9, 11], dtype='int64')
indA ^ indB #異或,輸出:Int64Index([1, 2, 9, 11], dtype='int64')
二、數據取值與選擇
(一) Series數據選擇方法
1. 將Series看作字典
data = pd.Series([0.25, 0.5, 0.75, 1.0], index=['a', 'b', 'c', 'd'])
data['b']
# 使用Python字典的表達式和方法檢測索引和值
'a' in data #輸出:True
data.keys() #輸出:Index(['a', 'b', 'c', 'd'], dtype='object')
list(data.items()) #輸出:[('a', 0.25), ('b', 0.5), ('c', 0.75), ('d', 1.0)]
# 增加新索引值擴展Series
data['e'] = 1.25
2. 將Series看作一維數組
# 數組數據選擇功能:索引、花哨索引等
# 將顯式索引作爲切片
data['a': 'c']
# 將隱式索引作爲切片
data[0:2]
# 掩碼
data[(data > 3) & (data < 0.8)]
# 花哨索引
data[['a', 'e']]
- 當使用顯式索引作切片時,結果包含最後一個索引;而當使用隱式索引作切片時,結果不包含最後一個索引。
3. 索引器:loc, iloc, ix
- 如果Series是顯式整數索引,那麼取值操作會使用顯式索引,切片操作會使用隱式索引。(容易混淆)
data = pd.Series(['a', 'b', 'c'], index=[1, 3, 5])
# 1 a
# 3 b
# 5 c
# dtype: object
# 取值操作是顯式索引
data[1] #輸出:'a'
# 切片操作是隱式索引
data[1:3]
# 3 b
# 5 c
# dtype: object
第一種索引器:loc
屬性,表示取值和切片都是顯式的
data.loc[1] #輸出:'a'
data.loc[1:3]
# 1 a
# 3 b
# dtype: object
第二種索引器:iloc
屬性,表示取值和切片都是隱式索引(左閉右開區間)
data.iloc[1] #輸出:'b'
data.iloc[1:3]
# 3 b
# 5 c
# dtype: object
第三種索引器:ix
,它是loc
和iloc
的混合形式,在Series對象中ix
等價於標準Python列表取值方式。ix
索引器主要用於DataFrame對象。
Python代碼的設計原則之一是“顯式優於隱式”,使用loc
和iloc
可以讓代碼更易維護,可讀性更高(尤其是在處理整數索引的對象時)
(二) DataFrame數據選擇方法
1. 將DataFrame看作字典(若干Series對象構成)
states
# pop area
# California 38332521 423967
# Texas 26448193 695662
# New York 19651127 141297
# 1. 通過對列名進行字典形式取值獲取數據(dictionary-style)
states['area']
# 2. 用屬性形式選擇純字符串列名的數據(attribute-style)
states.area
# 對同一個對象進行屬性形式與字典形式的列數據結果相同
states.area is states['area'] #輸出:True
# 如果列名不是純字符串,或者列名與DataFrame的方法同名,就不能用屬性索引
states.pop is states['pop'] #data.pop中,pop會顯示爲方法,無法獲取列,輸出:False
# 應該避免對用屬性形式選擇的列直接賦值
states['pop'] = z # ok
# states.pop = z # NO
# 可以用字典形式的語法調整對象:如,增加一列
states['density'] = states['pop'] / states['area']
# pop area density
# California 38332521 423967 90.413926
# Texas 26448193 695662 38.018740
# New York 19651127 141297 139.076746
2. 將DataFrame看作二維數組
# values屬性按行查看數組數據
states.values
# array([[3.83325210e+07, 4.23967000e+05, 9.04139261e+01],
# [2.64481930e+07, 6.95662000e+05, 3.80187404e+01],
# [1.96511270e+07, 1.41297000e+05, 1.39076746e+02]])
# 行列轉置
states.T
# 單個行索引獲取一行數據
states.values[0] #輸出:array([3.83325210e+07, 4.23967000e+05, 9.04139261e+01])
# 獲取列數據
states['area']
# 索引器
states.iloc[:2, :1]
states.loc[:'Texas', :'area']
states.ix[:2, :'pop'] #注意:ix索引器對於整數索引的處理容易混淆
# 索引器結合掩碼與花哨索引
states.loc[states.density > 100, ['pop', 'density']]
# pop density
#New York 19651127 139.076746
# 任意取值方法都可以用於調整數據
states.iloc[0, 2] = 90
3. 其他取值方法
# 如果對單個標籤取值就選擇列,而對多個標籤用切片就選擇行
states['California':'Texas']
# 切片也可以不用索引值,直接用行數實現
states[:1]
# 掩碼操作也可以直接對每一行進行過濾,而不需要使用loc索引器
states[states.density > 100]
三、Pandas數值運算方法
Pandas集成了NumPy的功能,除此之外,Pandas在保存數據內容與組合不同來源的數據具有優勢。
高效技巧:對於一元運算(如函數與三角函數)的通用函數將在輸出結果中保留索引和列標籤;對於二元運算(如加法和乘法),在傳遞通用函數時會自動對齊索引進行計算。
(一) 通用函數:保留索引
rng = np.random.RandomState(42)
ser = pd.Series(rng.randint(0, 10, 4))
ser
# 0 6
# 1 3
# 2 7
# 3 4
# dtype: int64
# Pandas對象使用NumPy通用函數,結果依然保留索引
np.exp2(ser)
# 0 64.0
# 1 8.0
# 2 128.0
# 3 16.0
# dtype: float64
(二) 通用函數:索引對齊
當在兩個Series或DataFrame對象上進行二元運算時,Pandas會在計算過程中對齊兩個對象的索引,這在處理不完整的數據時非常方便。
- Series索引對齊
- 整合兩個數據源的數據,運算結果數組的索引時兩個輸入數組索引的並集。
- 對於缺失位置的數據,Pandas會默認用NaN填充,表示此處無數。
- 可以通過運算符方法的
fill_value
參數自定義缺失值
area = pd.Series({'Alaska': 1723337, 'Texas': 695662, 'California': 423967}, name='area')
population = pd.Series({'California': 38332521, 'Texas': 26448193, 'New York': 19651127}, name='population')
population / area
# Alaska NaN
# California 90.413926
# New York NaN
# Texas 38.018740
# dtype: float64
area.index | population.index
# Index(['Alaska', 'California', 'New York', 'Texas'], dtype='object')
A = pd.Series([2, 4, 6], index=[0, 1, 2])
B = pd.Series([1, 3, 5], index=[1, 2, 3])
A + B
# 0 NaN
# 1 5.0
# 2 9.0
# 3 NaN
# dtype: float64
# 如需避免NaN值,就用對象方法代替運算符,設置參數自定義缺失的數據
A.add(B, fill_value=0)
# 0 2.0
# 1 5.0
# 2 9.0
# 3 5.0
# dtype: float64
- DataFrame索引對齊
rng = np.random.RandomState(42)
A = pd.DataFrame(rng.randint(0, 20, (2, 2)), columns=list('AB'))
# A B
# 0 6 19
# 1 14 10
B = pd.DataFrame(rng.randint(0, 10, (3, 3)), columns=list('BAC'))
# B A C
# 0 7 4 6
# 1 9 2 6
# 2 7 4 3
# 兩個對象的行列索引可以是不同順序的,結果的索引會自動按順序排列
A + B
# A B C
# 0 10.0 26.0 NaN
# 1 16.0 19.0 NaN
# 2 NaN NaN NaN
# 計算均值要用stack將二維數組壓縮成一維數組
fill = A.stack().mean()
A.add(B, fill_value=fill)
# A B C
# 0 10.00 26.00 18.25
# 1 16.00 19.00 18.25
# 2 16.25 19.25 15.25
Python運算符與Pandas方法的映射關係
Pandas運算符 Pandas方法
+ add()
- sub(), subtract()
* mul(), multiply()
/ truediv(), div(), divide()
// floordiv()
% mod()
** pow()
(三) 通用函數:DataFrame與Series的運算
# 根據NumPy廣播規則,讓二維數組減自身的一行數據會按行計算。Pandas等同。
A = rng.randint(10, size=(3, 4))
A - A[0]
df = pd.DataFrame(A, columns=list('QRST'))
df - df.iloc[0]
# 按列計算,要用運算符方法,通過axis參數設置
df.subtract(df['R'], axis=0)
halfrow = df.iloc[0, ::2]
df - halfrow
Pandas相關閱讀:
[Python3] Pandas v1.0 —— (一) 對象、數據取值與運算 【本文】
[Python3] Pandas v1.0 —— (二) 處理缺失值
[Python3] Pandas v1.0 —— (三) 層級索引
[Python3] Pandas v1.0 —— (四) 合併數據集
[Python3] Pandas v1.0 —— (五) 累計與分組
[Python3] Pandas v1.0 —— (六) 數據透視表
[Python3] Pandas v1.0 —— (七) 向量化字符串操作
[Python3] Pandas v1.0 —— (八) 處理時間序列
[Python3] Pandas v1.0 —— (九) 高性能Pandas: eval()與query()
總結自《Python數據科學手冊》