2、預備知識-python核心用法常用數據分析庫(下)
概述
Python 是當今世界最熱門的編程語言,而它最大的應用領域之一就是數據分析。在python眾多數據分析工具中,pandas是python中非常常用的數據分析庫,在數據分析,機器學習,深度學習等領域經常被使用。使用 Pandas 我們可以 Excel/CSV/TXT/MySQL 等數據讀取,然后進行各種清洗、過濾、透視、聚合分析,也可以直接繪制折線圖、餅圖等數據分析圖表,在功能上它能夠實現自動化的對大文件處理,能夠實現 Excel 的幾乎所有功能並且更加強大。
本實驗將通過實戰的方式,介紹pandas數據分析庫的基本使用,讓大家在短時間內快速掌握python的數據分析庫pandas的使用,為后續項目編碼做知識儲備
實驗環境
- Python 3.7
- Pycharm
任務二:Pandas數據分析實戰-1
【任務目標】
本任務主要目標為使用pandas進行數據分析實戰,在實戰過程中帶大家了解pandas模塊的一下功能:
- 了解數據
- 分析數據問題
- 清洗數據
- 整合代碼
【任務步驟】
1、准備工作
打開CMD窗口后,執行如下命令,打開jupyter notebook編輯器
jupyter notebook
成功執行以上命令后,系統將自動打開默認瀏覽器,如下圖所示:
成功打開瀏覽器后,按如下流程創建 notebook 文件
對新建notebook進行重命名操作
2、notebook 文件新建完成后,接下來在新建的 notebook 中編寫代碼
- 了解數據
在處理任何數據之前,我們的第一任務是理解數據以及數據是干什么用的。我們嘗試去理解數據的列/行、記錄、數據格式、語義錯誤、缺失的條目以及錯誤的格式,這樣我們就可以大概了解數據分析之前要做哪些“清理”工作。
本次我們需要一個 patient_heart_rate.csv 的數據文件,這個數據很小,可以讓我們一目了然。這個數據是 csv 格式。數據是描述不同個體在不同時間的心跳情況。數據的列信息包括人的年齡、體重、性別和不同時間的心率。
- 加載數據即查看數據集
import pandas as pd
df = pd.read_csv('data/patient_heart_rate.csv')
df.head()
運行結果如下:
分析數據問題
- 沒有列頭
- 一個列有多個參數
- 列數據的單位不統一
- 缺失值
- 重復數據
- 非 ASCII 字符
- 有些列頭應該是數據,而不應該是列名參數
3、清洗數據
3.1、 沒有列頭
如果我們拿到的數據像上面的數據一樣沒有列頭,Pandas 在讀取 csv 提供了自定義列頭的參數。下面我們就通過手動設置列頭參數來讀取 csv,代碼如下:
import pandas as pd
column_names= ['id', 'name', 'age', 'weight','m0006',
'm0612','m1218','f0006','f0612','f1218']
df = pd.read_csv('data/patient_heart_rate.csv', names = column_names)
df.head()
運行結果如下:
上面的結果展示了我們自定義的列頭。我們只是在這次讀取 csv 的時候,多了傳了一個參數 names = column_names,這個就是告訴 Pandas 使用我們提供的列頭。
4、一個列有多個參數
在數據中不難發現,Name 列包含了兩個參數 Firtname 和 Lastname。為了達到數據整潔目的,我們決定將 name 列拆分成 Firstname 和 Lastname
使用 str.split(expand=True),將列表拆成新的列,再將原來的 Name 列刪除
df[['first_name','last_name']] = df['name'].str.split(expand=True)
df.drop('name', axis=1, inplace=True)
df.head()
運行結果如下:
5、列數據的單位不統一
如果仔細觀察數據集可以發現 Weight 列的單位不統一。有的單位是 kgs,有的單位是 lbs
lbs_weight_s = df[df.weight.str.contains("lbs").fillna(False)]['weight']
lbs_weight_s = lbs_weight_s.apply(lambda lbs: "%.2fkgs" % (float(lbs[:-3])/2.2) )
df.loc[lbs_weight_s.index,'weight'] = lbs_weight_s
運行結果如下:
6、缺失值處理
在數據集中有些年齡、體重、心率是缺失的。我們又遇到了數據清洗最常見的問題——數據缺失。一般是因為沒有收集到這些信息。我們可以咨詢行業專家的意見。典型的處理缺失數據的方法:
- 刪:刪除數據缺失的記錄
- 贗品:使用合法的初始值替換,數值類型可以使用 0,字符串可以使用空字符串“”
- 均值:使用當前列的均值
- 高頻:使用當前列出現頻率最高的數據
- 源頭優化:如果能夠和數據收集團隊進行溝通,就共同排查問題,尋找解決方案。
7、重復數據處理
有的時候數據集中會有一些重復的數據,執行以下代碼觀察數據集前10條數據
df.head(10)
運行結果如下:
觀察以上結果,可以發現在我們的數據集中也存在重復的數據,如下
首先我們校驗一下是否存在重復記錄。如果存在重復記錄,就使用 Pandas 提供的 drop_duplicates() 來刪除重復數據。
df.drop_duplicates(['first_name','last_name'],inplace=True)
df.head(10)
運行結果如下:
刪除weight字段重復的數據
df.drop_duplicates(['weight'],inplace=True)
df.head(10)
運行結果如下
8、 非ASCII 字符
在數據集中 Fristname 和 Lastname 有一些非 ASCII 的字符。
處理非 ASCII 數據方式有多種
- 刪除
- 替換
- 僅僅提示一下
我們使用刪除的方式:
df['first_name'].replace({r'[^\x00-\x7F]+':''}, regex=True, inplace=True)df['last_name'].replace({r'[^\x00-\x7F]+':''}, regex=True, inplace=True)df.head()
運行結果如下:
9、有些列頭應該是數據,而不應該是列名參數
有一些列頭是有性別和時間范圍組成的,這些數據有可能是在處理收集的過程中進行了行列轉換,或者收集器的固定命名規則。這些值應該被分解為性別(m,f),小時單位的時間范圍(00-06,06-12,12-18)
sorted_columns = ['id','age','weight','first_name','last_name']df = pd.melt(df, id_vars=sorted_columns, var_name='sex_hour', value_name='puls_rate')df = df[df.puls_rate != '-'].dropna()df = df.sort_values(['id','first_name','last_name']).reset_index()def split_sex_date(sex_hour): sex = sex_hour[:1] if 'f' == sex: sex = '女' elif 'm' == sex: sex = '男' hour = sex_hour[1:] return pd.Series([sex,hour])df[['sex','hour']] = df.sex_hour.apply(split_sex_date)df.drop('sex_hour',axis=1)
運行結果如下:
任務三:Pandas數據分析實戰-2
【任務目標】
本任務主要目標為使用pandas進行數據分析實戰,在實戰過程中帶大家了解pandas模塊的一下功能:
- 日期的處理
- 字符編碼的問題
【任務步驟】
1、參考【任務一】第1步中操作,在jupyter notebook編輯中重新新建一個notebook 文件,命名為 pandas-data-processing-3,如下圖所示:
2、預覽數據
這次我們使用 Artworks.csv,我們選取 100 行數據來完成本次內容。具體步驟:
- 導入Pandas
- 讀取 csv 數據到 DataFrame(要確保數據已經下載到指定路徑)
DataFrame 是 Pandas 內置的數據展示的結構,展示速度很快,通過 DataFrame 我們就可以快速的預覽和分析數據。代碼如下:
import pandas as pddf = pd.read_csv('./data/Artworks.csv').head(100)df.head(10)
運行結果如下:
2、統計日期數據
我們仔細觀察一下 Date 列的數據,有一些數據是年的范圍(1976-1977),而不是單獨的一個年份。在我們使用年份數據畫圖時,就不能像單獨的年份那樣輕易的畫出來。我們現在就使用 Pandas 的 value_counts() 來統計一下每種數據的數量。
首先,選擇要統計的列,並調用 value_counts():
df['Date'].value_counts()
運行結果如下:
3、日期數據問題
Date 列數據,除了年份是范圍外,還有三種非正常格式。下面我們將這幾種列出來:
- 問題一,時間范圍(1976-77)
- 問題二,估計(c. 1917,1917 年前后)
- 問題三,缺失數據(Unknown)
- 問題四,無意義數據(n.d.)
接下來我們會處理上面的每一個問題,使用 Pandas 將這些不規則的數據轉換為統一格式的數據。
問題一和二是有數據的只是格式上欠妥當,問題三和四實際上不是有效數據。針對前兩個問題,我們可以通過代碼將據格式化來達到清洗的目的,然而,后兩個問題,代碼上只能將其作為缺失值來處理。簡單起見,我們將問題三和四的數據處理為0。
處理問題一
問題一的數據都是兩個年時間范圍,我們選擇其中的一個年份作為清洗之后的數據。為了簡單起見,我們就使用開始的時間來替換這樣問題的數據,因為這個時間是一個四位數的數字,如果要使用結束的年份,我們還要補齊前兩位的數字。
首先,我們需要找到問題一的數據,這樣我們才能將其更新。要保證其他的數據不被更新,因為其他的數據有可能是已經格式化好的,也有可能是我們下面要處理的。
我們要處理的時間范圍的數據,其中包含有“-”,這樣我們就可以通過這個特殊的字符串來過濾我們要處理的數據,然后,通過 split() 利用“-”將數據分割,將結果的第一部分作為處理的最終結果。
代碼如下
row_with_dashes = df['Date'].str.contains('-').fillna(False)for i, dash in df[row_with_dashes].iterrows(): df.at[i,'Date'] = dash['Date'][0:4]df['Date'].value_counts()
運行結果如下:
處理問題二
問題二的數據體現了數據本身的不准確性,是一個估計的年份時間,我們將其轉換為年份,那么,就只要保留最后四位數字即可,該數據的特點就是數據包含“c”,這樣我們就可以通過這一特征將需要轉換的數據過濾出來。
row_with_cs = df['Date'].str.contains('c').fillna(False)for i,row in df[row_with_cs].iterrows(): df.at[i,'Date'] = row['Date'][-4:]df[row_with_cs]
運行結果如下:
處理問題三四
將這問題三四的數據賦值成初始值 0
df['Date'] = df['Date'].replace('Unknown','0',regex=True)
df['Date'] = df['Date'].replace('n.d.','0',regex=True)
df['Date']
運行結果如下:
4、附:完成代碼
注意:完整代碼中刪除了數據展示部分
import pandas as pd
df = pd.read_csv('../data/Artworks.csv').head(100)
df.head(10)
df['Date'].value_counts()
row_with_dashes = df['Date'].str.contains('-').fillna(False)
for i, dash in df[row_with_dashes].iterrows():
df.at[i,'Date'] = dash['Date'][0:4]
df['Date'].value_counts()
row_with_cs = df['Date'].str.contains('c').fillna(False)
for i,row in df[row_with_cs].iterrows():
df.at[i,'Date'] = row['Date'][-4:]
df['Date'].value_counts()
df['Date'] = df['Date'].replace('Unknown','0',regex=True)
df['Date'] = df['Date'].replace('n.d.','0',regex=True)
df['Date'].value_counts()