給妹子講python-S02E13Series與DataFrame的數值運算
python,不管你懂沒懂,反正妹子是搞懂了
轉載請註明:知乎專欄《給妹子講python》--醬油哥
【要點搶先看】
1.DataFrame和Series一元運算會作用於每一個數據元素2.DataFrame間和Sereis間的二元運算會自動對齊索引,並進行缺失值處理3.DataFrame和Series之間可以進行行、列兩方向上的運算,同樣會對齊索引
介紹完Pandas對象的構造和數據獲取,這一集,我們來說說Series和DataFrame類型的數值運算。
首先說說一元運算,由於Pandas的底層是基於NumPy實現,所以自然而言一元運算會作用於Pandas數據類型的每個數據組成元素,並且保留行、列標籤索引。
我們來看兩個例子,第一個是Series對象的一元數值運算:
import pandas as pdimport numpy as npser = pd.Series([2,4,6,8], index=[a,b,c,d])print(ser)print(np.exp(ser))a 2b 4c 6d 8dtype: int64a 7.389056b 54.598150c 403.428793d 2980.957987dtype: float64
DataFrame數據對象的操作也是一樣的
import pandas as pdimport numpy as nprng = np.random.RandomState(18)df = pd.DataFrame(rng.randint(0,10,(3,4)), columns=[a,b,c,d])print(df)print(np.sin(df * np.pi / 4)) a b c d0 3 8 5 11 2 2 8 82 2 1 5 5 a b c d0 0.707107 -2.449294e-16 -7.071068e-01 7.071068e-011 1.000000 1.000000e+00 -2.449294e-16 -2.449294e-162 1.000000 7.071068e-01 -7.071068e-01 -7.071068e-01
提醒一句,在NumPy中使用的一元運算符,都是可以拿到Pandas數據對象中使用的。
接著說說二元運算。
在兩個Series之間或兩個DataFrame數據對象之間進行二元運算的時候,會自動在計算過程中對齊兩個對象的索引,如果一個索引僅在一個對象中出現,那麼另一個對象的索引空缺處會進行空值處理。
import pandas as pdimport numpy as npser1 = pd.Series({a:10,b:20,d:40})ser2 = pd.Series({b:2,c:3,d:4})print(ser1 / ser2)a NaNb 10.0c NaNd 10.0dtype: float64
從結果中我們很容易發現,結果中的索引是兩個輸入數組索引的並集,對於參與二元運算的兩個Series,缺失位置的數據,Pandas默認都會用NaN填充,並且有NaN參與的運算,其結果也是NaN。
不過我們可以打破這種默認,例如,我們可以設置參與運算的Series,其索引缺失位置的數據為0。
import pandas as pdimport numpy as npser1 = pd.Series({a:10,b:20,d:40})ser2 = pd.Series({b:2,c:3,d:4})print(ser1.add(ser2, fill_value=0))a 10.0b 22.0c 3.0d 44.0dtype: float64
DataFrame間的運算,當然也同樣會進行索引對齊:
import pandas as pdimport numpy as nprng = np.random.RandomState(10)A = pd.DataFrame(rng.randint(0, 20, (2, 2)), columns=[A, B])B = pd.DataFrame(rng.randint(0, 10, (3, 3)), columns=[B, C, A])print(A)print(B)print(A + B) A B0 9 41 15 0 B C A0 1 9 01 1 8 92 0 8 6 A B C0 9.0 5.0 NaN1 24.0 1.0 NaN2 NaN NaN NaN
這裡面我們要留意一點,我們看,B的列標籤是B,C,A的順序,當然這都不影響Pandas將參與二元運算的兩個DataFrame進行列對齊。
當然我們也可以用指定的非默認值來替換掉NaN,例如使用對象A的均值:
import pandas as pdimport numpy as nprng = np.random.RandomState(10)A = pd.DataFrame(rng.randint(0, 20, (2, 2)), columns=[A, B])B = pd.DataFrame(rng.randint(0, 10, (3, 3)), columns=[B, C, A])print(A)print(B)print(A.add(B, fill_value=A.stack().mean())) A B0 9 41 15 0 B C A0 1 9 01 1 8 92 0 8 6 A B C0 9.0 5.0 16.01 24.0 1.0 15.02 13.0 7.0 15.0
這裡在求A均值的時候用了一個stack函數,作用是把二維變數A壓縮成一個4元一維數組,這個方法後面還會再提的。
在這裡我補充一下,例如+,-,*,/這些屬於python運算符,如果我們需要加上一些控制用的關鍵字,如:填充缺失值fill_value,那麼就需要使用Pandas的對應方法add(),sub(),mul(),div()。
【妹子說】剛才我們說的都是Series和Series之間,DataFrame與DataFrame之間,那麼如果想進行DataFrame與Series之間的運算,該如何處理?
我們先看一個例子,讓DataFrame的每一行都減去由自己第一行數據構成的Series對象:
import pandas as pdimport numpy as nprng = np.random.RandomState(10)A = pd.DataFrame(rng.randint(0, 10, (3, 4)), columns=[A, B, C, D])print(A)print(A.iloc[0])print(A - A.iloc[0]) A B C D0 9 4 0 11 9 0 1 82 9 0 8 6A 9B 4C 0D 1Name: 0, dtype: int32 A B C D0 0 0 0 01 0 -4 1 72 0 -4 8 5
我們通過索引器iloc得到第一行數據(Series類型),然後用DataFrame每行數據減去第一行數據。
如果想在列方向上進行類似的DataFrame-Series操作,也不難做到:
import pandas as pdimport numpy as nprng = np.random.RandomState(10)A = pd.DataFrame(rng.randint(0, 10, (3, 4)), columns=[A, B, C, D])print(A)print(A[B])print(A.sub(A[B], axis=0)) A B C D0 9 4 0 11 9 0 1 82 9 0 8 60 41 02 0Name: B, dtype: int32 A B C D0 5 0 -4 -31 9 0 1 82 9 0 8 6
因為我們用到了指明列運算方向的參數axis=0,所以也必須使用Pandas的方法sub()。
我們發現,DataFrame與Series的運算同樣也是要對齊指定方向上的索引,索引不一致處的運算,也會用NaN進行空值處理。
import pandas as pdimport numpy as nprng = np.random.RandomState(10)A = pd.DataFrame(rng.randint(0, 10, (3, 4)), columns=[A, B, C, D])print(A)print(A.ix[0,[A, C]])print(A - A.ix[0,[A, C]]) A B C D0 9 4 0 11 9 0 1 82 9 0 8 6A 9C 0Name: 0, dtype: int32 A B C D0 0.0 NaN 0.0 NaN1 0.0 NaN 1.0 NaN2 0.0 NaN 8.0 NaN
【妹子說】總結一下吧,Series和DataFrame的數值運算,一元運算會對所有的數據元素進行運算,並保留索引值。二元運算核心之處就是索引對齊,索引缺失處默認用NaN進行處理。DataFrame與Sereis之間的運算,可以從行、列兩個方向上進行,同樣會進行索引缺失的處理。
推薦閱讀:
※非均衡數據處理--如何評價?
※科技巨頭都愛的Data Pipeline,如何自動化你的數據工作?
※實踐—簡單數據處理和分析
※Python數據科學(五)- 數據處理和數據採集