摘要:數據清洗大家好,這一期我將為大家帶來我的學習心得第二期數據清理。這一期我會和大家分享一些比較好用常見的清洗方法。首先還是讓我們來簡單看一下本文將會用到的數據源這是一個超小型的房地產行業的數據集,大家會在文章最后找到下載地址。
數據清洗
大家好,這一期我將為大家帶來我的pandas學習心得第二期:數據清理。這一步非常重要,一般在獲取數據源之后,我們緊接著就要開始這一步,以便為了之后的各種操作,簡單來說,我們的目標就是讓數據看起來賞心悅目,規規矩矩的,所以我們會對原始的dataframe做一些必要的美容,包括規范命名,去除異常值,重新選擇合適的index啊,處理缺失值,統一列的命名等等。
這一期我會和大家分享一些比較好用常見的清洗方法。首先還是讓我們來簡單看一下本文將會用到的數據源:
property_data.csv 這是一個超小型的房地產行業的數據集,大家會在文章最后找到下載地址。
這篇文章我會從以下幾個方面來和大家分享我的心得體會:
有關缺失值的處理
有關列的處理
設置Index
源碼及數據下載地址
1.有關缺失值的處理這里我們會用到 property_data.csv這個數據集,在開始處理缺失值之前,我們可以先話一分鐘仔細想想,為什么實際生活中的數據從來是不完整的,原因基本有幾個方面:
用戶忘記填寫字段
從舊數據庫手動傳輸時數據丟失
代碼中有bug
用戶不填寫非必須字段(比如注冊的時候)
因為這些原因,我每次在處理missing value的時候都會問自己兩個基礎問題:
數據集每一列有什么特點?
我們想要在處理后得到什么類型的數據(int,float,string,boolean)?
帶著這些疑問,我們可以開始了,首先讓我們簡單讀取一下數據,利用head函數看看前5行,如果你還對pandas的基礎知識有疑問,可以看看我上一篇文章:Pandas之旅(一): 讓我們把基礎知識一次擼完,申精干貨
import pandas as pd import numpy as np import os os.chdir("F:Python教程segmentfaultpandas_sharePandas之旅_02 數據清洗")
# Read csv file into a pandas dataframe df = pd.read_csv("property_data.csv") # Take a look at the first few rows df.head()
PID | ST_NUM | ST_NAME | OWN_OCCUPIED | NUM_BEDROOMS | NUM_BATH | SQ_FT | |
---|---|---|---|---|---|---|---|
0 | 100001000.0 | 104.0 | PUTNAM | Y | 3 | 1 | 1000 |
1 | 100002000.0 | 197.0 | LEXINGTON | N | 3 | 1.5 | -- |
2 | 100003000.0 | NaN | LEXINGTON | N | NaN | 1 | 850 |
3 | 100004000.0 | 201.0 | BERKELEY | 12 | 1 | NaN | 700 |
4 | NaN | 203.0 | BERKELEY | Y | 3 | 2 | 1600 |
現在讓我們看看數據的一些關鍵列是什么:
ST_NUM:街道號碼
ST_NAME: 街道名稱
OWN_OCCUPIED: 是否用于自住
NUM_BEDROOMS:臥室數量
SQ_FT:面積
這里可以給大家普及點房地產知識,有的時候房屋用途被明確規定,比如有的房產寫的是"owner occupied only ")意思是說如果你買了,那這個房子會成為你的主要住所,不能用于出租之類的,簡單理解就是自住
所以現在我可以自問自答第一個問題:數據集每一列有什么特點?
ST_NUM:float或int ...
ST_NAME:string
OWN_OCCUPIED:string ... Y(“是”)或N(“否”)
NUM_BEDROOMS:float或int,數字類型
SQ_FT:float或int,數字類型
1.1 規范的缺失值標記現在讓我們關注ST_NUM這一列:
# Looking at the ST_NUM column df["ST_NUM"]
0 104.0 1 197.0 2 NaN 3 201.0 4 203.0 5 207.0 6 NaN 7 213.0 8 215.0 Name: ST_NUM, dtype: float64
如果想查看該列的缺失值情況,我們可以利用isnull()方法,如果出現缺失值,會返回True,反之返回false
df["ST_NUM"].isnull()
0 False 1 False 2 True 3 False 4 False 5 False 6 True 7 False 8 False Name: ST_NUM, dtype: bool
但是其實如果我們打開csv文件,你會發現第3行是空白,還有一行在該列顯示的是NA,所以結論已經有了:在pandas里表示缺省值的符號及時NA,換句話說,如果我們要表示缺省值,標準寫法是NA
1.2 不規范的缺失值標記同樣的,這回讓我們關注一下NUM_BEDROOMS這一列,我們發現出現了4種類型的表達缺省值的標記:
n/a
NA
—
na
通過剛才的實踐,我們已經確定NA是pandas可以識別的,那么其他的符號呢,現在讓我們來測試一下
df["NUM_BEDROOMS"]
0 3 1 3 2 NaN 3 1 4 3 5 NaN 6 2 7 1 8 na Name: NUM_BEDROOMS, dtype: object
df["NUM_BEDROOMS"].isnull()
0 False 1 False 2 True 3 False 4 False 5 True 6 False 7 False 8 False Name: NUM_BEDROOMS, dtype: bool
可以看到pandas識別了n/a 和NA兩種符號,但是接下來我們要考慮一個問題,假設你是房地產公司的地區總經理,你每周會收到不同地區的負責人提交的表格,
這些人中有的喜歡用--表示空白值,有的人喜歡用na,那應該怎么辦?
最簡單的方式就是將所有表示空白值的符號統一放在list中,讓后讓pandas一次性識別:
# Making a list of missing value types missing_values = ["na", "--"] df = pd.read_csv("property_data.csv", na_values = missing_values)
現在我們來看看到底發生了什么?
df
PID | ST_NUM | ST_NAME | OWN_OCCUPIED | NUM_BEDROOMS | NUM_BATH | SQ_FT | |
---|---|---|---|---|---|---|---|
0 | 100001000.0 | 104.0 | PUTNAM | Y | 3.0 | 1 | 1000.0 |
1 | 100002000.0 | 197.0 | LEXINGTON | N | 3.0 | 1.5 | NaN |
2 | 100003000.0 | NaN | LEXINGTON | N | NaN | 1 | 850.0 |
3 | 100004000.0 | 201.0 | BERKELEY | 12 | 1.0 | NaN | 700.0 |
4 | NaN | 203.0 | BERKELEY | Y | 3.0 | 2 | 1600.0 |
5 | 100006000.0 | 207.0 | BERKELEY | Y | NaN | 1 | 800.0 |
6 | 100007000.0 | NaN | WASHINGTON | NaN | 2.0 | HURLEY | 950.0 |
7 | 100008000.0 | 213.0 | TREMONT | Y | 1.0 | 1 | NaN |
8 | 100009000.0 | 215.0 | TREMONT | Y | NaN | 2 | 1800.0 |
我們可以發現只要missing_value中記錄的表達空白值的符號,全部變成了規整的NaN
1.3 類型不一致的異常值剛剛我們已經簡單了解了在pandas中如何處理缺失值的,還有一種情況,讓我們來看OWN_OCCUPIED這一列,這一列的答案只能是Y,N 但是我們發現數據集意外地出現了12,屬于類型不對稱
df["OWN_OCCUPIED"].isnull()
0 False 1 False 2 False 3 False 4 False 5 False 6 True 7 False 8 False Name: OWN_OCCUPIED, dtype: bool
現在我們發現12是異常值,因為它是類型錯誤,所以我們可以簡單通過下面這個方法來檢測,
# Detecting numbers cnt=0 for row in df["OWN_OCCUPIED"]: try: int(row) df.loc[cnt, "OWN_OCCUPIED"]=np.nan except ValueError: pass cnt+=1
我們這里的策略是:
循環遍歷OWN_OCCUPIED列
嘗試將條目轉換為整數
如果條目可以更改為整數,請輸入缺失值
如果數字不能是整數,我們知道它是一個字符串,所以繼續
這樣我們會把OWN_OCCUPIED這一列中所有類型不對的值轉化為NaN,現在來看結果:
df["OWN_OCCUPIED"]
0 Y 1 N 2 N 3 NaN 4 Y 5 Y 6 NaN 7 Y 8 Y Name: OWN_OCCUPIED, dtype: object1.4 匯總缺失值
pandas提供了更為簡潔的方式,可以讓我們整體了解所有column的空值:
df.isnull().sum()
PID 1 ST_NUM 2 ST_NAME 0 OWN_OCCUPIED 2 NUM_BEDROOMS 3 NUM_BATH 1 SQ_FT 2 dtype: int64
或者如果我們只想知道數據是否存在空值,那么可以使用以下的命令:
# Any missing values? df.isnull().values.any()
True1.5 替換缺失值
如果我們想要替換掉缺失值,可以用fillna方法
# Replace missing values with a number df["ST_NUM"].fillna(125, inplace=True)
或者我們可以通過準確定位來替換缺失值:
# Location based replacement df.loc[2,"ST_NUM"] = 125
替換缺失值的一種非常常見的方法是使用中位數:
# Replace using median median = df["NUM_BEDROOMS"].median() df["NUM_BEDROOMS"].fillna(median, inplace=True) df
PID | ST_NUM | ST_NAME | OWN_OCCUPIED | NUM_BEDROOMS | NUM_BATH | SQ_FT | |
---|---|---|---|---|---|---|---|
0 | 100001000.0 | 104.0 | PUTNAM | Y | 3.0 | 1 | 1000.0 |
1 | 100002000.0 | 197.0 | LEXINGTON | N | 3.0 | 1.5 | NaN |
2 | 100003000.0 | 125.0 | LEXINGTON | N | 2.5 | 1 | 850.0 |
3 | 100004000.0 | 201.0 | BERKELEY | NaN | 1.0 | NaN | 700.0 |
4 | NaN | 203.0 | BERKELEY | Y | 3.0 | 2 | 1600.0 |
5 | 100006000.0 | 207.0 | BERKELEY | Y | 2.5 | 1 | 800.0 |
6 | 100007000.0 | 125.0 | WASHINGTON | NaN | 2.0 | HURLEY | 950.0 |
7 | 100008000.0 | 213.0 | TREMONT | Y | 1.0 | 1 | NaN |
8 | 100009000.0 | 215.0 | TREMONT | Y | 2.5 | 2 | 1800.0 |
現在假設因為一些需求,需要我們統一修改列名,把列名改為小寫,我們可以結合列表推導式輕易實現
df.rename(str.lower, axis="columns",inplace =True) df.columns
Index(["pid", "st_num", "st_name", "own_occupied", "num_bedrooms", "num_bath", "sq_ft"], dtype="object")
或者需要把列名中的_改為-:
new_cols = [c.replace("_","-") for c in df.columns] change_dict =dict(zip(df.columns,new_cols)) df.rename(columns=change_dict,inplace=True) df
pid | st-num | st-name | own-occupied | num-bedrooms | num-bath | sq-ft | |
---|---|---|---|---|---|---|---|
0 | 100001000.0 | 104.0 | PUTNAM | Y | 3.0 | 1 | 1000.0 |
1 | 100002000.0 | 197.0 | LEXINGTON | N | 3.0 | 1.5 | NaN |
2 | 100003000.0 | 125.0 | LEXINGTON | N | 2.5 | 1 | 850.0 |
3 | 100004000.0 | 201.0 | BERKELEY | NaN | 1.0 | NaN | 700.0 |
4 | NaN | 203.0 | BERKELEY | Y | 3.0 | 2 | 1600.0 |
5 | 100006000.0 | 207.0 | BERKELEY | Y | 2.5 | 1 | 800.0 |
6 | 100007000.0 | 125.0 | WASHINGTON | NaN | 2.0 | HURLEY | 950.0 |
7 | 100008000.0 | 213.0 | TREMONT | Y | 1.0 | 1 | NaN |
8 | 100009000.0 | 215.0 | TREMONT | Y | 2.5 | 2 | 1800.0 |
這里我沒有寫的精簡一些,反而是復雜了,主要是想讓大家回憶起之前我分享的dict使用技巧中的內容,注意這里inplace=True,導致的結果是我們的的確確修改了df所有的列名
2.1 根據需求新增列假如目前我們需要新增一列,根據房屋面積大小來賦值,我們先隨意把缺失值補上:
df["sq-ft"].fillna("0.0")
0 1000 1 0.0 2 850 3 700 4 1600 5 800 6 950 7 0.0 8 1800 Name: sq-ft, dtype: object
然后新建一列rank來根據房屋面積大小賦值S=small,M=medium,B=big:
df["rank"]= pd.cut(df["sq-ft"], [0, 800, 1600, np.inf], labels=("S","M","B")) df
pid | st-num | st-name | own-occupied | num-bedrooms | num-bath | sq-ft | rank | |
---|---|---|---|---|---|---|---|---|
0 | 100001000.0 | 104.0 | PUTNAM | Y | 3.0 | 1 | 1000.0 | M |
1 | 100002000.0 | 197.0 | LEXINGTON | N | 3.0 | 1.5 | NaN | NaN |
2 | 100003000.0 | 125.0 | LEXINGTON | N | 2.5 | 1 | 850.0 | M |
3 | 100004000.0 | 201.0 | BERKELEY | NaN | 1.0 | NaN | 700.0 | S |
4 | NaN | 203.0 | BERKELEY | Y | 3.0 | 2 | 1600.0 | M |
5 | 100006000.0 | 207.0 | BERKELEY | Y | 2.5 | 1 | 800.0 | S |
6 | 100007000.0 | 125.0 | WASHINGTON | NaN | 2.0 | HURLEY | 950.0 | M |
7 | 100008000.0 | 213.0 | TREMONT | Y | 1.0 | 1 | NaN | NaN |
8 | 100009000.0 | 215.0 | TREMONT | Y | 2.5 | 2 | 1800.0 | B |
具體實現方法我們之后會說,這里主要是用到了pandas的cut方法,非常便捷
3. 設置Index在許多情況下,使用數據的唯一值標識字段作為其索引是有幫助的。這里可能我們的數據不太合適,因此我們先偽造一列Fake_Index來模擬真實場景中的真正索引
df["Fake_Index"]=["A00"+str(i) for i in range(len(df))] df
pid | st-num | st-name | own-occupied | num-bedrooms | num-bath | sq-ft | rank | Fake_Index | |
---|---|---|---|---|---|---|---|---|---|
0 | 100001000.0 | 104.0 | PUTNAM | Y | 3.0 | 1 | 1000.0 | M | A000 |
1 | 100002000.0 | 197.0 | LEXINGTON | N | 3.0 | 1.5 | NaN | NaN | A001 |
2 | 100003000.0 | 125.0 | LEXINGTON | N | 2.5 | 1 | 850.0 | M | A002 |
3 | 100004000.0 | 201.0 | BERKELEY | NaN | 1.0 | NaN | 700.0 | S | A003 |
4 | NaN | 203.0 | BERKELEY | Y | 3.0 | 2 | 1600.0 | M | A004 |
5 | 100006000.0 | 207.0 | BERKELEY | Y | 2.5 | 1 | 800.0 | S | A005 |
6 | 100007000.0 | 125.0 | WASHINGTON | NaN | 2.0 | HURLEY | 950.0 | M | A006 |
7 | 100008000.0 | 213.0 | TREMONT | Y | 1.0 | 1 | NaN | NaN | A007 |
8 | 100009000.0 | 215.0 | TREMONT | Y | 2.5 | 2 | 1800.0 | B | A008 |
現在我們添加的最后一列非常像真正的房屋Id了,讓我們來看看這個偽造的索引是不是唯一值,可以利用is_unique來檢驗:
df.Fake_Index.is_unique
True
沒有問題,現在我們可以放心地把這列設置為我們真正的索引:
df = df.set_index("Fake_Index") df
pid | st-num | st-name | own-occupied | num-bedrooms | num-bath | sq-ft | rank | |
---|---|---|---|---|---|---|---|---|
Fake_Index | ||||||||
A000 | 100001000.0 | 104.0 | PUTNAM | Y | 3.0 | 1 | 1000.0 | M |
A001 | 100002000.0 | 197.0 | LEXINGTON | N | 3.0 | 1.5 | NaN | NaN |
A002 | 100003000.0 | 125.0 | LEXINGTON | N | 2.5 | 1 | 850.0 | M |
A003 | 100004000.0 | 201.0 | BERKELEY | NaN | 1.0 | NaN | 700.0 | S |
A004 | NaN | 203.0 | BERKELEY | Y | 3.0 | 2 | 1600.0 | M |
A005 | 100006000.0 | 207.0 | BERKELEY | Y | 2.5 | 1 | 800.0 | S |
A006 | 100007000.0 | 125.0 | WASHINGTON | NaN | 2.0 | HURLEY | 950.0 | M |
A007 | 100008000.0 | 213.0 | TREMONT | Y | 1.0 | 1 | NaN | NaN |
A008 | 100009000.0 | 215.0 | TREMONT | Y | 2.5 | 2 | 1800.0 | B |
現在對數據的操作容易多了,我們很多事情可以通過索引完成:
# 根據索引名稱切片 df["A000":"A003"]
pid | st-num | st-name | own-occupied | num-bedrooms | num-bath | sq-ft | rank | |
---|---|---|---|---|---|---|---|---|
Fake_Index | ||||||||
A000 | 100001000.0 | 104.0 | PUTNAM | Y | 3.0 | 1 | 1000.0 | M |
A001 | 100002000.0 | 197.0 | LEXINGTON | N | 3.0 | 1.5 | NaN | NaN |
A002 | 100003000.0 | 125.0 | LEXINGTON | N | 2.5 | 1 | 850.0 | M |
A003 | 100004000.0 | 201.0 | BERKELEY | NaN | 1.0 | NaN | 700.0 | S |
# 根據索引位置切片 df.iloc[1:3, 0:3]
pid | st-num | st-name | |
---|---|---|---|
Fake_Index | |||
A001 | 100002000.0 | 197.0 | LEXINGTON |
A002 | 100003000.0 | 125.0 | LEXINGTON |
# 定位到具體元素 df.iloc[1,2]
"LEXINGTON"總結
我把這一期的ipynb文件和py文件放到了GIthub上,大家如果想要下載可以點擊下面的鏈接:
Github倉庫地址: https://github.com/yaozeliang/pandas_share
這一期先講到這里,希望大家能夠繼續支持我,完結,撒花
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/43325.html
摘要:下面讓我們開始提速假設我們現在的電價是定值,不根據用電時間段來改變,那么中最快的方法那就是采用,這就是一個簡單的矢量化操作示范。它基本是在中運行最快的方式。 Pandas 加速 大家好,今天我們來看有關pandas加速的小技巧,不知道大家在剛剛接觸pandas的時候有沒有聽過如下的說法 pandas太慢了,運行要等半天 其實我想說的是,慢不是pandas的錯,大家要知道pandas本身...
為什么你需要pandas 大家好,今天想和大家分享一下有關pandas的學習新的,我因工作需要,從去年12月開始接觸這個非常好用的包,到現在為止也是算是熟悉了一些,因此發現了它的強大之處,特意想要和朋友們分享,特別是如果你每天和excel打交道,總是需要編寫一些vba函數或者對行列進行groupby啊,merge,join啊之類的,相信我,pandas會讓你解脫的。 好啦,閑話少說,這篇文章的基礎...
摘要:有關字符串基本方法大家好,我又回來了之前的幾期我們已經簡單了解了的基礎操作,但是只要涉及到數據,最常見的就是字符串類型,所以很多時候我們其實都在和字符串打交道,所以今天,我會把我自己總結的,有關字符串的常用方法分享給大家,希望能夠幫到各位小 有關字符串基本方法 大家好,我又回來了! 之前的幾期我們已經簡單了解了pandas的基礎操作,但是只要涉及到數據,最常見的就是String(字符串...
摘要:不為人知的七大實用技巧大家好,我今天勤快地回來了,這一期主要是和大家分享一些的實用技巧,會在日常生活中大大提升效率,希望可以幫助到大家還是老樣子,先給大家奉上這一期的章節目錄自定義選項,設置實用中模塊構建測試數據巧用訪問器合并其他列拼接使用 Pandas不為人知的七大實用技巧 大家好,我今天勤快地回來了,這一期主要是和大家分享一些pandas的實用技巧,會在日常生活中大大提升效率,希望...
摘要:如何根據需要創建簡單模型大家好,今天這一期我想和大家分享有關于創建模型的部分,首先讓我們來看一個比較常見的場景你每天需要打開個進行相同的操作,各種眼花繚亂的函數后老眼昏花。。。。 Pandas 如何根據需要創建簡單模型 大家好,今天這一期我想和大家分享有關于pandas創建模型的部分,首先讓我們來看一個比較常見的場景: 你每天需要打開N個excel進行相同的操作,各種眼花繚亂的VBA函...
閱讀 1038·2021-11-15 18:11
閱讀 3162·2021-09-22 15:33
閱讀 3458·2021-09-01 11:42
閱讀 2653·2021-08-24 10:03
閱讀 3615·2021-07-29 13:50
閱讀 2925·2019-08-30 14:08
閱讀 1274·2019-08-28 17:56
閱讀 2259·2019-08-26 13:57