淺談pandas,pyspark 的大數據ETL實踐經驗

作者:王雅寧

目錄


0.序言

本文主要以基於AWS 搭建的EMR spark 託管集羣,使用pandas pyspark 對合作單位的業務數據進行ETL —- EXTRACT(抽取)、TRANSFORM(轉換)、LOAD(加載) 等工作爲例介紹大數據數據預處理的實踐經驗,很多初學的朋友對大數據挖掘,數據分析第一直觀的印象,都只是業務模型,以及組成模型背後的各種算法原理。往往忽視了整個業務場景建模過程中,看似最普通,卻又最精髓的數據預處理或者叫數據清洗過程。


1. 數據接入

我們經常提到的ETL是將業務系統的數據經過抽取、清洗轉換之後加載到數據倉庫的過程,首先第一步就是根據不同來源的數據進行數據接入,主要接入方式有三:

  • 1.批量數據
    可以考慮採用使用備份數據庫導出dmp,通過ftp等多種方式傳送,首先接入樣本數據,進行分析
  • 2.增量數據
    考慮使用ftp,http等服務配合腳本完成
  • 2.實時數據
    消息隊列接入,kafka,rabbitMQ 等

數據接入對應ETL 中的E—-EXTRACT(抽取),接入過程中面臨多種數據源,不同格式,不同平臺,數據吞吐量,網絡帶寬等多種挑戰。

python 這種膠水語言天然可以對應這類多樣性的任務,當然如果不想編程,還有:Talend,Kettle,Informatica,Inaplex Inaport等工具可以使用.


這裏寫圖片描述
e.g. 一個kettle 的作業流

以上不是本文重點,不同數據源的導入導出可以參考:
數據庫,雲平臺,oracle,aws,es導入導出實戰
我們從數據接入以後的內容開始談起。


2. 髒數據的清洗

比如在使用Oracle等數據庫導出csv file時,字段間的分隔符爲英文逗號,字段用英文雙引號引起來,我們通常使用大數據工具將這些數據加載成表格的形式,pandas ,spark中都叫做dataframe

對與字段中含有逗號回車等情況,pandas 是完全可以handle 的,spark也可以但是2.2之前和gbk解碼共同作用會有bug

數據樣例

1,2,3
"a","b,
c","d"
"4","6,7","8"

pandas

# -*- coding:utf-8 -*-
"""@author:season@file:testCSV.py@time:2018/5/3110:49"""
import  pandas

def sum_analysis(filename,col_names):
    # 讀csv文件
    data = pandas.read_csv(filename,names=col_names,\
    engine='python', dtype=str)
    # 返回前n行
    first_rows = data.head(n=2)
    print(first_rows)
    # 返回全部列名
    cols = data.columns
    print(cols)
    # 返回維度
    dimensision = data.shape
    print(dimensision)
    print(data.info())
    return data

def main():
    col_names = ['1','2','3']
    file_test = u'''test.csv'''
    print(sum_analysis(file_test,col_names))

if __name__=='__main__':
    main()


這裏寫圖片描述
pandas 加載的 result

pyspark

sdf = spark.read.option("header","true") \
                 .option("charset","gbk") \
                 .option("multiLine", "true") \
                  .csv("s3a://your_file*.csv")
pdf = sdf.limit(1000).toPandas()

linux 命令

強大的sed命令,去除兩個雙引號中的換行

**處理結果放入新文件**
sed ':x;N;s/\nPO/ PO/;b x' INPUTFILE  > OUTPUTFILE
**處理結果覆蓋源文件**
sed -i ':x;N;s/\nPO/ PO/;b x' INPUTFILE

當然,有些情況還有由於文件編碼造成的亂碼情況,這時候就輪到linux命令大顯神威了。

比如 使用enconv 將文件由漢字編碼轉換成utf-8

enconv -L zh_CN -x UTF-8 filename

或者要把當前目錄下的所有文件都轉成utf-8   

enca -L zh_CN -x utf-8 *     

在Linux中專門提供了一種工具convmv進行文件名編碼的轉換,可以將文件名從GBK轉換成UTF-8編碼,或者從UTF-8轉換到GBK。

下面看一下convmv的具體用法:

convmv -f 源編碼 -t 新編碼 [選項] 文件名
#將目錄下所有文件名由gbk轉換爲utf-8
convmv -f GBK -t UTF-8 -r --nosmart --notest /your_directory

3. 缺失值的處理

pandas

pandas使用浮點值NaN(Not a Number)表示浮點數和非浮點數組中的缺失值,同時python內置None值也會被當作是缺失值。

如果其中有值爲None,Series會輸出None,而DataFrame會輸出NaN,但是對空值判斷沒有影響。DataFrame使用isnull方法在輸出空值的時候全爲NaN

例如對於樣本數據中的年齡字段,替換缺失值,並進行離羣值清洗

pdf["AGE"] = pd.to_numeric(pdf["AGE"],"coerce").fillna(500.0).astype("int")

pdf[(pdf["AGE"] > 0) & (pdf["AGE"] < 150)]

自定義過濾器過濾

#Fix gender
def fix_gender(x):
    if x is None:
        return None
    if "男" in x:
        return "M"
    if "女" in x:
        return "F"
pdf["PI_SEX"] = pdf["PI_SEX"].map(fix_gender)
or
pdf["PI_SEX"] = pdf["PI_SEX"].apply(fix_gender)

或者直接刪除有缺失值的行

data.dropna()

pyspark
spark 同樣提供了,.dropna(…) ,.fillna(…) 等方法,是丟棄還是使用均值,方差等值進行填充就需要針對具體業務具體分析了


4. 數據質量覈查與基本的數據統計

對於多來源場景下的數據,需要敏銳的發現數據的各類特徵,爲後續機器學習等業務提供充分的理解,以上這些是離不開數據的統計和質量覈查工作,也就是業界常說的讓數據自己說話。

4.1 統一單位

多來源數據 ,突出存在的一個問題是單位不統一,比如度量衡,國際標準是米,然而很多北美國際習慣使用英尺等單位,這就需要我們使用自定義函數,進行單位的統一換算。

4.2 去重操作

pandas

去重操作可以幫助我們統計業務的核心數據,從而迅速抓住主要矛盾。例如,對於互聯網公司來說,每天有很多的業務數據,然而發現其中的獨立個體的獨立行爲纔是數據分析人員應該注意的點。

data.drop_duplicates(['column'])

pyspark

使用dataframe api 進行去除操作和pandas 比較類似

sdf.select("column1","column2").dropDuplicates()

當然如果數據量大的話,可以在spark環境中算好再轉化到pandas的dataframe中,利用pandas豐富的統計api 進行進一步的分析。

pdf = sdf.select("column1","column2").dropDuplicates().toPandas()

使用spark sql,其實我覺的這個spark sql 對於傳統的數據庫dba 等分析師來說簡直是革命性產品, 例如:如下代碼統計1到100測試中每一個測試次數的人員分佈情況

count_sdf.createOrReplaceTempView("testnumber")

count_sdf_testnumber = spark.sql("\
SELECT tests_count,count(1) FROM \
testnumber where tests_count < 100 and lab_tests_count > 0 \
group by tests_count \
order by count(1) desc")

count_sdf_testnumber.show()

4.3 聚合操作與統計

pyspark 和pandas 都提供了類似sql 中的groupby 以及distinct 等操作的api,使用起來也大同小異,下面是對一些樣本數據按照姓名,性別進行聚合操作的代碼實例

sdf.groupBy("SEX").agg(F.count("NAME")).show()

labtest_count_sdf = sdf.groupBy("NAME","SEX","PI_AGE").agg(F.countDistinct("CODE").alias("tests_count"))

順帶一句,pyspark 跑出的sql 結果集合,使用toPandas() 轉換爲pandas 的dataframe 之後只要通過引入matplotlib, 就能完成一個簡單的可視化demo 了。


這裏寫圖片描述
樣例數據

d2 = pd.DataFrame({
    'label': [1,2,3],
    'count': [10,2,3],})

d2.plot(kind='bar')
plt.show()
d2.plot.pie(labels=['1', '2', '3'],subplots=True, figsize=(8, 4))
plt.show()


這裏寫圖片描述
直方圖,餅圖


參考文獻

做Data Mining,其實大部分時間都花在清洗數據
http://www.raincent.com/content-10-8092-1.html
基於PySpark大規模數據預處理
https://www.jianshu.com/p/b7882e9616c7


更多資訊,請關注公衆號

這裏寫圖片描述


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章