1. 程式人生 > >學習Pandas的一些記錄

學習Pandas的一些記錄

最近也是剛剛開始學Pandas,個人感覺功能太強大導致有些混亂。。。(可能是我剛開始接觸吧 )。為了便於記憶,整理下這幾天用到的一些東西。
首先這個是我要處理的資料,長這個樣子。

其實就是一個CSV檔案,在Pandas中,有專門讀取CSV的函式。

    data = pd.read_csv('train2.csv')

返回的型別為dataFrame,這是一個在pandas中非常重要的型別。將csv讀到data後,我們可以直接print出來,其實就和用excel看沒啥區別,這對我來說沒什麼用,但有一個info()函式挺有用的。

print data.info()

然後會打印出下邊的結果。

這裡寫圖片描述

有了這個其實就比肉眼來看好多了,它把裡邊的每列的資訊都告訴我了。首先看資料型別,裡邊有float64,int64,object這三種,查了一下,除了這三種以外,pandas中還有時間型別datetime和布林型bool。
然後就開始處理資料,首先可以看到其中有四列資料為0,也就是全空,這個就沒啥用了,可以直接把這四列刪了,pandas裡邊提供了多種刪除的辦法,比如drop(),這個函式就是可以根據你給的列的名字就可以刪除對應的列了,用法很簡單,具體怎麼用可以檢視下官方文件。但其實這裡就有第一個問題了,雖然也不是太大的問題,但作為一個懶人,我覺得如果有一份新的資料,裡邊有1W列(假如啊),其中300個是空的,我不至於要把這300個列名都寫上吧。。(可能是我目前只知道這個函式是這麼用的)。所以我就繼續找有沒有別的方法,然後就發現了一個更好的選擇。
pandas裡對於空資料用NAN表示,然後自然的,它就有函式對空資料項處理。dropna()就是幹這個的。這是

文件。它的作用就是幫你檢測空資料然後刪去,這裡邊有個how引數,就是關於用什麼方式做標準,它有兩個選擇,一個是any,就是隻有檢測到有nan,就直接全部刪了(預設是刪行。。畢竟一下子刪一列太變態),然後第二個是all,意思就是隻有全部為nan才刪掉。。這個不就是我要找的嗎?所以程式碼就可以這樣寫,

clean_data = data.dropna(how = 'all',axis = 1)

這樣就達到了我的目的哈哈,其中axis =1就表示按照列來檢測。其實這個函式還有幾個引數,我覺得也挺有用的可能以後會用到。第一個就是inplace,這個引數在pandas很多方法裡邊都有,它是一個布林型引數,預設都為False,它就是說你的這些操作是在原資料上做還是複製一個新的,這裡我就用的預設,因為我還在學啊,萬一把原資料搞壞咋辦。。還有個引數是thresh,這個看名字其實就知道了,設定它的作用就是既不是按照all,也不是按照any,而是按照你個的值來刪,只要滿足缺失值大於等於thresh的行(或列),就刪除。
現在空列刪完後,我本來是打算就開始處理缺失資料(後面談)了,但程式碼寫完後發現有錯,一直找了半天原因都不知道為什麼,當時忘記錯誤截圖了,情景就是我在做求均值等運算,貌似是有些值不能求什麼的。反正感覺邏輯上說不通,不知道怎麼錯了。一度陷入不知道咋辦的地步。最後沒辦法,我拿出絕招。。不就8000多個數據嗎,我特麼一個一個看看。。。。然後。。。結果真的就讓我很崩潰,裡邊竟然有這麼一行。。。
這裡寫圖片描述


我了個去,這是什麼鬼。。真讓人無語啊。然後,這次我其實多了個心眼,會不會還有別的坑爹資料,我就又稍微細看了一些。然後。。在年齡這一列又發現了些奇怪的東西。
這裡寫圖片描述
這裡寫圖片描述
人家都是數字,冒出來些漢字什麼鬼,其實後來我又執著的看了許多。。發現類似的問題還真不少。現在問題找到了,就要想辦法解決了。其實最初當我剛找到很多*那行時候,我就試了一種很2b的方法,直接用上邊提到的drop()函式,把那一行刪了,但當我後邊又發現很多像年齡裡出現漢字什麼的的時候我就發現我錯了,假設如果以後遇到更大的資料,難道都要先肉眼找錯嗎?那我還寫什麼程式碼,直接刪了不就完了。所以,為了不白白浪費我的眼力,我就開始查方法。其實一開始我的想法是就年齡來說,我把那幾個特殊的(前提是。。。我用肉眼全看了一遍全部找出來了。。。),根據值找出來,然後刪了對應行,後來發現。。這麼做又何前邊的想法有什麼區別呢。我要忘記我用肉眼尋找的慘痛經歷!
當然在這裡有一點要記一下,可能我過於小白了,網上很多教程定位行啊,列啊什麼的都是在講pandas的強大的索引定位能力,這裡就不提了(其實我也沒怎麼用)。事實上,我覺得很多情況,首先是就這次這個資料,我根本不可能知道我想要的某個資料的索引,我只知道我想找的某個資料的某一項的值。那麼怎麼找呢,其實很簡單,比如我想找年齡為2的一條記錄,可以這麼寫

    data = pd.read_csv(path)
    print data[data['age']=='2']

這樣就會打印出年齡欄位為2的行。
這裡寫圖片描述
如果要附加些限制,就直接加上與運算就好了,比如想找同時性別為2的行,則
這裡寫圖片描述
有點跑偏了。繼續我的問題,現在假設我根本沒用肉眼看過這些資料(實在是太累了),那就不知道現在所知道的一切了。那怎麼處理呢。繼續想辦法,查閱資料的過程中發現了一個匹配函式,isin(),這裡不介紹了,直接給文件,作用也是根據想找的內容去找行。但這個並不適合我要解決的問題,因為我現在不知道要找什麼。這個時候我想到了正則表示式!!我的資料全是數字啊,(按理說就不該有那些字串呀。這也是pandas將那些列讀取為object型別而不是int或者float的原因),帶著這個想法,發現了pandas中果然有模糊匹配的方法!叫做contains()。嗨呀,果然好用。然後先上文件,找到後怎麼用呢。其實這些就不太難了。首先先來個正則表示式吧。

regex = r'\d+\.?\d*$'

對於正則表示式我也不是很熟,不過這個網上隨便一搜到處都是,我寫的這個第一部分\d+就是前邊要有至少一個數字,因為考慮到年齡、性別啥的就是整數嘛(雖然是object型別),然後.?是判斷有一個或者沒有小數點. ,這個就判斷了可以是小數或者不是了,後邊\d*$就是有0個或者n個數字了,加了個$是因為。。我知道有那種1月。2月。。的坑爹情況,反正就算沒有加上也保險嘛,數字肯定以數字結尾嘛。寫完正則,就要用上邊提到的那個函數了,先上程式碼

for col in clean_data.select_dtypes([np.object]).columns:
        clean_data = clean_data[clean_data[col].str.contains(regex,na = False) ]

這裡一個迴圈是找出哪些列是object型別的,因為只有這裡邊才會有坑爹的資料啊。。select_dtype()函式很簡單,看文件,然後contains()裡邊的na引數很重要,開始時候沒加這個老報錯,首先contains,首先contains返回的是布林型資料,我們也是靠這個來直接篩選行的,false的化就直接沒了,這是pandas因為支援布林型來選擇行列。之前沒加na=False報錯的原因是因為,我們的資料有些為nan,這時候就沒東西去匹配了,所以就報錯了,設定引數False後,就直接把這種情況當作False考慮了,這可能會丟失些有用的資料,但也沒辦法了目前,可能還有更好的方法。這樣下來過後,我的資料就不存在那些亂七八糟的字元了。可以看下結果。
這裡寫圖片描述
發現這時候資料變成列8451個了。
然後要做的就是處理那些正常的資料了,就是那些型別為float和int的資料。其實上邊提到了關於nan的刪除,有刪除就有填充,畢竟資料不能因為少一個就直接全部丟掉。所以pandas裡邊有個fillna()函式,有了前邊刪除的基礎,這個就很簡單了。這裡文件。這裡我選擇的是將每列的中衛數作為填充,填在了缺失處,因為大概看了下資料,有個describe()函式可以看資料的max,min等等資訊,感覺用就用中衛數來填了。。其實這不重要,會填就行了,填什麼以後再考慮。程式碼很簡單。

    for col in clean_data.select_dtypes([np.float,np.int]).columns:
        clean_data[col].fillna(clean_data[col].median(),inplace=True)

然後再看一下結果,
這裡寫圖片描述
現在就沒有空值了,哈哈。現在就可以
然後看了下生成的新的csv,發現有兩列基本全是0,那肯定對後邊做訓練沒啥用了,就直接用drop()函式刪了,其實也可以寫個判斷0個數來刪,但太麻煩了,偷了個懶就直接按照列號刪了。

總結
pandas其實真的好用,文件和網上他人的部落格也很多,但實際用時會發現每個人的需求可能都不一樣,具體怎麼用還要根據具體情況,不斷積累。