天天看點

爬蟲練習之資料清洗——基于Pandas

本次以51Job上在東莞地區爬取的以Java為關鍵詞的招聘資料
包括salary company time job_name address字段
           

當我把招聘網站上的資料爬下來的時候,内心是很開心的

爬下來的原始資料

但是!

What?!

這是什麼資料?

而且還不止一條!!!

待清洗資料

第一次資料清洗

根據上述截圖可以發現,髒資料都包含了xx元/小時以及xx元/天。一般我們IT行業很少以小時或者以天計算工資(如果擔心清洗了正确的資料,可以後面再做檢驗)

思路

首先尋找合适的Pandas函數

清理資料相關的函數有
drop()
duplicated()
drop_duplicates()
dropna()
           

我們并不是要去重, 而是要删掉這部分資料

但是在網絡上搜尋清洗資料, 我找半天找不到對應的答案, 大部分都是去重, 替換, 去除空資料等等. 我決定跟着自己的思路, 利用drop函數來實作資料清洗

先help一下

drop(self, labels, axis=0, level=None, inplace=False, errors='raise') method of pandas.core.frame.DataFrame instance
    Return new object with labels in requested axis removed.
    
    Parameters
    ----------
    labels : single label or list-like
    axis : int or axis name
    level : int or level name, default None
        For MultiIndex
    inplace : bool, default False
        If True, do operation inplace and return None.
    errors : {'ignore', 'raise'}, default 'raise'
        If 'ignore', suppress error and existing labels are dropped.
    
        .. versionadded:: 0.16.1
    
    Returns
    -------
    dropped : type of caller
           

可以看到, labels是必選參數, 支援單個或者清單

找出髒資料

從drop函數的幫助文檔,我們可以想到這樣的思路.

先找到對應的髒資料, 再把這些髒資料的index清單找到, 通過drop函數把index對應的所有資料删除

根據上面的思路, 找pandas函數

一開始我找的是query(), where, loc等,但發現不知道怎麼模糊查詢, 用like報錯了

最後查找到

# 這樣将得到true or false
df['字段'].str.contains(r'正規表達式')

# 這樣才能得到DataFrame
df[df['字段'].str.contains(r'正規表達式')]

# 具體代碼
df_dirty = df[df['salary'].str.contains(r'(小時|天)+')]
           

确認無誤并删除

# df.index傳回一個index清單
df_clean = df.drop(df_dirty.index)
           

檢驗是否删除成功

df.info()
df_dirty.info()
df_clean.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 354 entries, 0 to 353
Data columns (total 5 columns):
salary      354 non-null object
company     354 non-null object
time        354 non-null object
job_name    354 non-null object
address     354 non-null object
dtypes: object(5)
memory usage: 13.9+ KB
<class 'pandas.core.frame.DataFrame'>
Int64Index: 28 entries, 5 to 321
Data columns (total 5 columns):
salary      28 non-null object
company     28 non-null object
time        28 non-null object
job_name    28 non-null object
address     28 non-null object
dtypes: object(5)
memory usage: 1.3+ KB
<class 'pandas.core.frame.DataFrame'>
Int64Index: 326 entries, 0 to 353
Data columns (total 5 columns):
salary      326 non-null object
company     326 non-null object
time        326 non-null object
job_name    326 non-null object
address     326 non-null object
dtypes: object(5)
memory usage: 15.3+ KB

           

可以看到,髒資料已經被删除

完整代碼

import pandas as pd
import numpy as np

df = pd.read_csv(r'PycharmProjects/JobCrawler/job.csv')

df_dirty = df[df['salary'].str.contains(r'(小時|天)+')]
df_clean = df.drop(df_dirty.index)

           

幾行代碼就搞定, 再一次感受到Python的簡潔, 時間花在思考上更多

第二次資料清洗

這次針對的是job_name字段, 方式和第一次清洗的方式相同

待清洗資料-job_name

可以發現為了躲避清理, 這些招聘資訊搞出來的各種名字, 連*号都出現了

# 加上這一行就可以找出job_name字段的髒資料啦
df_dirty = df[df['job_name'].str.contains(r'(\*|在家|試用|體驗)+')]
           
import numpy as np
import pandas as pd

df = pd.read_csv(r'PycharmProjects/JobCrawler/job.csv')

df_dirty_salary = df[df['salary'].str.contains(r'(小時|天)+')]

df_dirty_job_name = df[df['job_name'].str.contains(r'(\*|在家|試用|體驗|無需|無須|試玩|紅包)+')]

df_dirty = pd.concat([df_dirty_salary, df_dirty_job_name])

df.drop(df_dirty.index)

df_clean = df.drop(df_dirty.index)

df_clean
           

參考文獻

使用python進行資料清洗
http://bluewhale.cc/2016-08-21/python-data-cleaning.html

正規表達式 - 文法
http://www.runoob.com/regexp/regexp-syntax.html

Pandas合并資料集
http://blog.csdn.net/u010414589/article/details/51135840