[Python3] Pandas v1.0 —— (一) 對象、數據取值與運算


[ 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
  1. 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])
  1. 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']
  1. 創建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對象

  1. 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屬性:indexcolumns

# DataFrame有index屬性獲取索引標籤
states.index 	#輸出:Index(['California', 'Texas', 'New York'], dtype='object')

# DataFrame有columns屬性存放列標籤的index對象
states.columns 	#輸出:Index(['population', 'area'], dtype='object')
  1. DataFrame是特殊的字典:一列映射一個Series的數據
states['area']
# California    423967
# Texas         695662
# New York      141297
# Name: area, dtype: int64
  1. 創建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對象

  1. 將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 不可賦值
  1. 將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,它是lociloc混合形式,在Series對象中ix等價於標準Python列表取值方式。ix索引器主要用於DataFrame對象

Python代碼的設計原則之一是“顯式優於隱式”,使用lociloc可以讓代碼更易維護,可讀性更高(尤其是在處理整數索引的對象時)

(二) 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會在計算過程中對齊兩個對象的索引,這在處理不完整的數據時非常方便。

  1. 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
  1. 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數據科學手冊》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章