我的Pandas應用場景(2)


上文交代了一些啰嗦事,本文開始,就要來點實際的了。

先來一個比較簡單的場景:

Given:一個包括N(極其復雜,這里取3個)個列的DataFrame:df,df包括index;

And:對df所有列元素進行一些處理,得到df的一個變換后的df_new;

And:對df_new的某些列做極其復雜的判斷,得到新的列result;

When:需要將要根據result對df進行分析;

Then:將result追加到df中。

上述的場景是我的一個算法驗證的場景,簡單地說,就是需要通過對原始數據進行變換,然后得到新的列,然后追加到原始數據中,最后進行分析。

首先構造一下模擬的數據吧。我們的數據通過隨機數產生,為10*3的數據,每一列的名稱為A/B/C,放到csv格式的文件中,文件內容如下所示:

A,B,C
4.556325895482557,4.9467487190814206,9.240498646959768
6.798122785026925,9.205498509979439,6.495701755638054
1.7088666262153485,1.9490481646738644,5.016719349132167
7.68793618140002,4.288529993589748,0.4479283787649413
0.22238136867848257,2.861119654701667,5.296500633944277
3.8352546975711,0.29287579880826087,1.0438719791356377
4.603712955967749,5.647815101448938,0.6054047619225811
6.916870514198006,8.903690009637602,4.836793019361064
9.845396552800361,0.8159084013183737,0.8425827491512894
2.425545747141858,7.353661205806686,2.982326067390466

一般字符型的文件會以上述的逗號隔開的方式存儲,通過pandas的read_csv()可以方便的讀入數據到DataFrame,如下代碼所示:

import pandas as pd
import numpy as np

df = pd.read_csv('d:/data.csv')

pd.read_csv()默認的讀法就是上述代碼那樣,他會將第一行當做列名讀入。假如我們的csv數據中不包含列名,可以通過header=None來禁止將第一行當做列名;假如csv數據中沒有列名,而我們想要指定列名,這也是我經常做的,可以通過name=[]參數,通過一個列表指定所有列的名稱。指定列名有一個好處就是列名可以當做DataFrame的屬性,對列進行訪問,后續會介紹。

讀進來的輸入如下所示:

 

然后,我們需要對df進行變換。

這里模擬一種變換,就是將每一列進行均值位0,方差為1的變換,代碼如下:

import pandas as pd
import numpy as np

df = pd.read_csv('d:/data.csv')

df_new = df.apply(lambda col: (col - col.mean()) * 1.0 / col.std())
df_new

其中,df.apply()函數是df的一個函數式接口,表示依次對df的列(A/B/C)進行迭代,其參數為一個lambda表達式,lambda的參數col就表示df的一個列。

col其實是Series的一個對象,其中包含大量的數據處理方法,這里實用的是其中兩個:均值mean()和std()方差。

lambda的實現部分使用了Pandas的向量化的運算方式,也就是說col雖然是一個Series,但是我們對其操作就像操作一個標量一樣,但是自動傳播給所有的元素。

經過上述代碼的運算,每一列都被映射到新的df_new中,這個方式在機器學習、數據挖掘中很常見。結果如下圖所示。

  A B C
0 -0.102247 0.100417 1.865099
1 0.652462 1.435738 0.944303
2 -1.060854 -0.839506 0.448149
3 0.952021 -0.105966 -1.084541
4 -1.561285 -0.553528 0.542008
5 -0.344998 -1.358795 -0.884620
6 -0.086294 0.320234 -1.031713
7 0.692439 1.341107 0.387790
8 1.678338 -1.194799 -0.952147
9 -0.819582 0.855099 -0.234328

現在,我們要使用df_new的數據計算我們的結果了。如果邏輯很簡單,則可以直接通過Pandas的IF THEN邏輯實現,復雜的算法可以需要自己一行一行的遍歷df_new,通過if else邏輯實現。我們先說一個簡單的情況。

假如,我們的算法是這樣的:如果A>0.5並且B<0.5,則為True,否則如果C>0.5,則為True,則否為False,實現代碼如下所示:

import pandas as pd
import numpy as np

df = pd.read_csv('d:/data.csv')

df_new = df.apply(lambda col: (col - col.mean()) * 1.0 / col.std())

df_new.ix[(df_new.A > 0.5) & (df_new.B < 0.5), 'Result'] = True
df_new.ix[~((df_new.A > 0.5) & (df_new.B < 0.5)) & (df_new.C > 0.5), 'Result'] = True
df_new.ix[~(~((df_new.A > 0.5) & (df_new.B < 0.5)) & (df_new.C > 0.5)), 'Result'] = False
df_new

結果如下所示:

 

Out[68]:
  A B C Result
0 -0.102247 0.100417 1.865099 True
1 0.652462 1.435738 0.944303 True
2 -1.060854 -0.839506 0.448149 False
3 0.952021 -0.105966 -1.084541 False
4 -1.561285 -0.553528 0.542008 True
5 -0.344998 -1.358795 -0.884620 False
6 -0.086294 0.320234 -1.031713 False
7 0.692439 1.341107 0.387790 False
8 1.678338 -1.194799 -0.952147 False
9 -0.819582 0.855099 -0.234328 False

由於算法邏輯不是很復雜,抽象起來也就三個情況,所以通過Pandas的IF Then的機制實現了Result列的添加。

DataFrame.ix[condition, 'newOrExistsColname'] = value,具體可以參考Pandas的十分鍾入門教程,開始就是講這個的。

需要強調的是我們通過df_new.A這樣的方式訪問A列元素,這是Pandas的方便之處;並且各種比較和& ~操作都是針對元素的;並且只有index相同的元素才會比較,而且Result也是添加到對應的index列的。

假如算法實現在太復雜,不是簡單的集中情況可以講清楚的,這個時候我采用的方法就是C++和Java中最常使用的for循環了,幾乎萬能。還以上述的算法為例,代碼如下:

import pandas as pd
import numpy as np

df = pd.read_csv('d:/data.csv')

df_new = df.apply(lambda col: (col - col.mean()) * 1.0 / col.std())

result = pd.Series([False]*len(df_new))
for i in range(len(df_new)):
    item = df_new.iloc[i, :]
    if item.A > 0.5 and item.B < 0.5:
        result[i] = True
    elif item.C > 0.5:
        result[i] = True
    else:
        result[i] = False # unnecessary
df_new['Result'] = result
df_new

 

代碼中一片濃郁的C、Java風格,雖然不那么函數式也不向量化,但是我就是感覺熟悉,畢竟我最早學習的是C。

首先,我定義了一個Series,初始化為False,然后通過一個for循環,遍歷df_new的所有行,依次為result賦值,最后,通過df_new['newcolname']=的方式將resut追加到df_new中了。

注意,當將Series往DataFrame或者Series中拼接的時候,默認的都是安裝index對齊的,也就是行的index一致的才會拼接到一起,而與行的順序無關,這點是Pandas的強大之處(數據的自動對齊,在groupby之后的數據中特別有用),千萬別忽視了這點。

最后,我們要將df_new.Result追加給df,因為df_new.Result本質上還是一個Series,所以上述的代碼中已經有了一種方式:df.ix['Result']=df_new.Result。

代碼如下:

import pandas as pd
import numpy as np

df = pd.read_csv('d:/data.csv')

df_new = df.apply(lambda col: (col - col.mean()) * 1.0 / col.std())

result = pd.Series([False]*len(df_new))
for i in range(len(df_new)):
    item = df_new.iloc[i, :]
    if item.A > 0.5 and item.B < 0.5:
        result[i] = True
    elif item.C > 0.5:
        result[i] = True
    else:
        result[i] = False # unnecessary
df_new['Result'] = result
df['Result'] = df_new.Result
df

 

最終結果如下:

 

Out[77]:
  A B C Result
0 4.556326 4.946749 9.240499 True
1 6.798123 9.205499 6.495702 True
2 1.708867 1.949048 5.016719 False
3 7.687936 4.288530 0.447928 True
4 0.222381 2.861120 5.296501 True
5 3.835255 0.292876 1.043872 False
6 4.603713 5.647815 0.605405 False
7 6.916871 8.903690 4.836793 False
8 9.845397 0.815908 0.842583 True
9 2.425546 7.353661 2.982326 False

 

 

本文要點:

Pandas讀取CSV文件方法;

Pandas的追加新列方法:df.ix[condition, 'newcolname'] = value(標量或者向量) 或者 df['newcolname'] = value(標量或者向量);

Pandas的df.apply()對列進行迭代的方法;

Pandas的df中的一些常用的數據處理方法;

Pandas的Series的簡單邏輯操作& | ~;

看,是不是很簡單。

未完待續……

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM