Python:Pandas的基本操作和使用
Pandas整體內容概要
本文整體介紹
- Pands的資料結構
- Pands的讀取與儲存
- 資料的基本操作:資料的檢視、檢查、選擇、刪減、填充
- 資料的處理:合併、聚合、分組、filter、sort、groupBy
- 函式應用與對映
- 資料的簡單視覺化
Pandas 是非常著名的開源資料處理庫,其基於 NumPy 開發,該工具是 Scipy 生態中為了解決資料分析任務而設計。Pandas 納入了大量庫和一些標準的資料模型,提供了高效地操作大型資料集所需的函式和方法。
我們可以通過它完成對資料集進行快速讀取、轉換、過濾、分析等一系列操作。除此之外,Pandas 擁有強大的缺失資料處理與資料透視功能,可謂是資料預處理中的必備利器。
1.Pandas的資料結構
特有的資料結構是 Pandas 的優勢和核心。簡單來講,我們可以將任意格式的資料轉換為 Pandas 的資料型別,並使用 Pandas 提供的一系列方法進行轉換、操作,最終得到我們期望的結果。
Pandas 的資料型別主要有以下幾種,它們分別是:
- Series(一維陣列)
- DataFrame(二維陣列) -- 是不是與sparkSQL等大資料框架中的DataFrame很類似,其實可以理解就是一個東西,一個二維表格 + 一個Schema = 一個DataFrame,或 Series + Series = DataFrame
- Panel(三維陣列)
- Panel4D(四維陣列)
- PanelND(更多維陣列)
其中 Series 和 DataFrame 應用的最為廣泛,本文僅對 Series 和 DataFrame 進行討論
Series
Series 是 Pandas 中最基本的一維陣列形式。其可以儲存整數、浮點數、字串等型別的資料。
其基本結構為:
pandas.Series(data=None, index=None)
data 可以是字典,或者NumPy 裡的 ndarray 物件等
index 是資料索引
可以看出,其結構與Array或者List等資料結構也有相似型,每個資料都有個索引,可以根據索引快速定位資料。
Series的生成
通過傳入一個iterable物件,比如列表、range物件、迭代器等都可以生成一個Series。pd.Series方法可以自動給生成一個0開始的索引,也可以指定索引
也可以傳入Python的字典來建立Series,則key為索引,value為資料
注意: 特別宣告,在建立Series時指定的index的優先順序要高於values,表現在生成的Series嚴格按照指定的index排序,執行下列語句體會一下
由於 Pandas 基於 NumPy 開發。那麼 NumPy 的資料型別 ndarray 多維陣列自然就可以轉換為 Pandas 中的資料。而 Series 則可以基於 NumPy 中的一維資料轉換。
s = pd.Series(np.random.randn(5))
其他訪問方式
相比傳統的資料結構,Series擁有更高層的訪問索引方式,比如序列索引、布林索引
因為布林索引是非常常用的一種索引方式,所以這裡再強調一下。布林索引實質上就是傳入布林值組成的iterable物件比如[False,True,True] , 通過布林運算 series_3 >= 'b 得到的結果其實就是[False,True,True]
布林運算可以通過'與'(&)、'或'(|)、'非'(~)進行組合運算 , (每一個計算項一定要加括號,注意運算子的優先順序)
DataFrame
關於DataFrame在不同技術棧中的不同理解,其實本質是相同的,左圖是pandas中的理解,右圖為spark DataFrame的經典圖示
其實可以理解就是一個東西,一個二維表格 + 一個Schema = 一個DataFrame,或 Series + Series = DataFrame
dataframe是在Series的基礎上添加了一個軸,原來的行索引index稱為0軸(axis=0),新增軸列索引columns稱為1軸(axis=1) 1軸的優先順序要高於0軸
由python物件可以快速建立DataFrame , 同Series一樣,沒有指定index會由pandas自動建立
dict_2 = {'A':[1,2,3],'B':['a','b','c']} # 1軸優先順序高,指定key時表示的是1軸,如果想要類似Series一樣指定index,需要用巢狀字典
dataframe_1 = pd.DataFrame(dict_2,index=range(1,4)) # 可以指定index
dataframe_1
也可以指定列索引的額順序
dataframe_2 = pd.DataFrame(dict_2,index=range(1,4),columns=['B','A']) # 同上面演示的Series的index一樣,可以指定列索引的順序
dataframe_2
獲取列索引
預設對dataframe進行索引是執行列索引,得到一個Series,指定的column退化為Series的name屬性
# 兩種訪問方式都可以
print(dataframe_2.B )
print(dataframe_2['B'] )
#訪問某個元素,先指定列再指定行
print(dataframe_2['A'][2]) #2不可以加引號,為索引號
新增或修改某一列的值
新增或修改某一列只需要類似賦值的操作,賦值一個iterable物件
指定 series或者dict會對index/key進行匹配,只賦值key與index匹配的value
刪除columns:兩種方法
行列轉置(0軸和1軸的轉置)
2.資料的讀取與儲存
資料的讀取
pandas的I/O API是一組read函式,比如pandas.read_csv()函式。這類函式可以返回pandas物件。相應的write函式是像DataFrame.to_csv()一樣的物件方法。下面是一個方法列表,包含了這裡面的所有readers函式和writer函式。
該部分可參見官方文件,或pandas中文網 https://www.pypandas.cn/docs/user_guide/io.html#csv-文字檔案
- pd.read_csv(filename):從CSV檔案匯入資料
- pd.read_table(filename):從限定分隔符的文字檔案匯入資料
- pd.read_excel(filename):從Excel檔案匯入資料
- pd.read_sql(query, connection_object):從SQL表/庫匯入資料
- pd.read_json(json_string):從JSON格式的字串匯入資料
- pd.read_html(url):解析URL、字串或者HTML檔案,抽取其中的tables表格
- pd.read_clipboard():從你的貼上板獲取內容,並傳給read_table()
- pd.DataFrame(dict):從字典物件匯入資料,Key是列名,Value是資料
常用的方法的讀取引數解釋 - pd.read_csv(filename):從CSV檔案匯入資料
下列為常用的引數及解釋
引數 | 解釋 | 必填/非必填 |
---|---|---|
filepath_or_buffer | 檔案路徑 | 必填 |
sep | 指定分隔符,預設逗號',' | 非必填 |
header | 指定第幾行作為表頭。預設為0(即第1行作為表頭),若沒有表頭,需設定header=None,可以是int或list。 | 非必填 |
names | 指定列的名稱,用list表示,預設None | 非必填 |
index_col | 指定行索引,可以是一列或多列,預設None | 非必填 |
usecols | 需要讀取的列,可以使用列序列也可以使用列名,預設None | 非必填 |
prefix | 給列名新增字首。如prefix=x,會出來X0,X1,....,預設None | 非必填 |
skiprows | 需要忽略的行數(從檔案開始處算起),或需要跳過的行號列表(從0開始),預設None | 非必填 |
skipfooter | 需要忽略的行數(從最後一行開始算) | 非必填 |
nrows | 需要讀取的行數(從檔案頭開始算起),預設None | 非必填 |
encoding | 編碼方式,亂碼時使用,預設None | 非必填 |
另附上公司大佬整理的常用引數,以供參考,膜拜大佬
資料的儲存
常用的方式,更全面請詳見官檔
- df.to_csv(filename):匯出資料到CSV檔案
- df.to_excel(filename):匯出資料到Excel檔案
- df.to_sql(table_name, connection_object):匯出資料到SQL表
- df.to_json(filename):以Json格式匯出資料到文字檔案
loc/iloc方式訪問DataFrame
3. 資料的基本操作:資料的檢查、檢視、選擇、刪減、填充
在pandas中,使用的最多的資料結構是series和DataFrame,以下操作更多的基於這兩者進行。
常用資料檢查方法
常用方法 | 介紹 |
---|---|
df.head() | 預設顯示前 5 條 |
df.tail(7) | 指定顯示後 7 條,不填為5條 |
df.describe() | 對資料集進行概覽,會輸出該資料集每一列資料的計數、最大值、最小值,std,25%,50%,75%值等 |
df.values | 將 DataFrame 轉換為 NumPy 陣列 |
df.index | 檢視索引 |
df.columns | 檢視列名 |
df.shape | 檢視形狀,如(n,m)n行m列 |
df.mean() | 返回所有列的均值 |
df.corr() | 返回列與列之間的相關係數 |
df.count() | 返回每一列中的非空值的個數 |
df.median() | 返回每一列的中位數 |
... | count,min,max,std.. |
pd.isnull() | 檢查DataFrame物件中的null值,並返回一個Boolean陣列 |
pd.notnull() | 檢查DataFrame物件中的非null值,並返回一個Boolean陣列 |
pd.isna() | 檢查DataFrame物件中的空值(null和''),並返回一個Boolean陣列 |
pd.notna() | 檢查DataFrame物件中的非空值(非null和非''),並返回一個Boolean陣列 |
s.value_counts(dropna=False) | 檢視Series物件的唯一值和計數 |
df.apply(pd.Series.value_counts) | 檢視DataFrame物件中每一列的唯一值和計數 |
常用資料檢視選擇方法
在資料預處理過程中,我們往往會對資料集進行切分,只將需要的某些行、列,或者資料塊保留下來,輸出到下一個流程中去。這也就是所謂的資料選擇,或者資料索引。由於 Pandas 的資料結構中存在索引、標籤,所以我們可以通過多軸索引完成對資料的選擇。
基於索引數字選擇
當我們新建一個 DataFrame 之後,如果未自己指定行索引或者列對應的標籤,那麼 Pandas 會預設從 0 開始以數字的形式作為行索引,並以資料集的第一行作為列對應的標籤。其實,這裡的「列」也有數字索引,預設也是從 0 開始,只是未顯示出來
我們可以用.iloc 方法對資料集進行基於索引數字的選擇。Selection by Position i可理解為index,與下方的loc區分開
該方法可接受的索引為:
- 整數;
- 整數構成的列表或陣列,例如:[1, 2, 3];
- 布林陣列;
- 可返回索引值的函式或引數。
選擇示例
方法 | 介紹 |
---|---|
df.iloc[:3] | 選擇前3行,類似Python的切片 |
df.iloc[5] | 選擇特定一行 |
df.iloc[[1, 3, 5]] | 選擇1,3,5行,注意不是 df.iloc[1, 3, 5],df.iloc[] 的 [[行],[列]] 裡面可以同時接受行和列的位置 |
df.iloc[:, 1:4] | 選擇2-4列,注意:df.iloc[] 的 [[行],[列]] 裡面可以同時接受行和列的位置 |
df.iloc[:3, 1:4] | 選擇前3行的2-4列,#訪問指定的index和columns,注意此處指的是索引,所以是前閉後開區間 |
基於標籤名稱選擇
直接根據標籤對應的名稱選擇,為 df.loc[]。loc為Selection by Label函式
df.loc[] 可以接受的型別有:
- 單個標籤。例如:2 或 'a',這裡的 2 指的是標籤而不是索引位置。
- 列表或陣列包含的標籤。例如:['A', 'B', 'C']。
- 切片物件。例如:'A':'E',注意這裡和上面切片的不同之處,首尾都包含在內。
- 布林陣列。
- 可返回標籤的函式或引數。
常用方法 | 介紹 |
---|---|
df.loc[0:2] | 訪問前3條(和index無關,和順序有關) |
df.loc[[0, 2, 4]] | 選擇1,3,5行 |
df.loc[:, 'A':'B'] | 選擇A,B列 |
df.loc[:, 'A':] | 選擇A列後面的列 |
資料刪減/清理
df.drop(labels=['A','B'], axis=1) | 直接去掉資料集中指定的列和行。一般在使用時,我們指定 labels 標籤引數,然後再通過 axis 指定按列或按行刪除即可。 |
df.drop_duplicates | 剔除資料集中的重複值。使用方法非常簡單,指定去除重複值規則,以及 axis 按列還是按行去除即可 |
df.dropna() | 刪除所有包含空值的行 |
df.dropna(axis=1) | 刪除所有包含空值的列 |
df.dropna(axis=1,thresh=n) | 刪除所有小於n個非空值的行 |
資料填充/替換
常用方法 | 介紹 |
---|---|
df.fillna(x) | 用x替換DataFrame物件中所有的空值(null和''),也可以新增引數method='pad'和method='bfill'使用缺失值前面/後面的值進行完全填充,可通過limit= 引數設定連續填充的限制數量 |
df.fillna(df.mean()['C':'E']) | 通過C,E列的平均值來填充na值 |
s.astype(float) | 將Series中的資料型別更改為float型別 |
s.replace(1,'one') | 用‘one’代替所有等於1的值 |
s.replace([1,3],['one','three']) | 用'one'代替1,用'three'代替3 |
df.rename(columns=lambda x: x + 1) | 批量更改列名 |
df.rename(columns={'old_name': 'new_ name'}) | 選擇性更改列名 |
df.set_index('column_one') | 更改索引列 |
df.rename(index=lambda x: x + 1) | 批量重新命名索引 |
插值填充
還有一種比較符合資料趨勢的填充方式,插值填充,是利用資料的變化趨勢來填充
# 生成一個 DataFrame
df = pd.DataFrame({'A': [1.1, 2.2, np.nan, 4.5, 5.7, 6.9],
'B': [.21, np.nan, np.nan, 3.1, 11.7, 13.2]})
df
df_interpolate = df.interpolate() # 線性插值
df_interpolate
下面是插值插入的兩個資料,
對於 interpolate() 支援的插值演算法,也就是 method=。建議
- 如果你的資料增長速率越來越快,可以選擇 method='quadratic'二次插值。
- 如果資料集呈現出累計分佈的樣子,推薦選擇 method='pchip'。
- 如果需要填補預設值,以平滑繪圖為目標,推薦選擇 method='akima'。
最後提到的 method='akima',需要你的環境中安裝了 Scipy 庫。除此之外,method='barycentric' 和 method='pchip' 同樣也需要 Scipy 才能使用
4. 資料的處理:合併、聚合、分組、filter、sort、groupBy
合併
- merge 實現兩個DataFrame通過value或index連線成一張寬表的操作,是基於column連線
- join 基於兩個DataFrame的索引進行合併,是基於索引連線
- concat 兩個DataFrame按照0軸或1軸拼接成一個DataFrame(即行拼接或列拼接)
merge方法
pd.merge(df1,df2,how='inner',on='column')
引數
df1/df2:左/右位置的dataframe。
how:資料合併的方式。left:基於左dataframe列的資料合併;right:基於右dataframe列的資料合併;outer:基於列的資料外合併(取並集);inner:基於列的資料內合併(取交集);預設為'inner'。
on:用來合併的列名,這個引數需要保證兩個dataframe有相同的列名。on=['A','B']
left_on/right_on:左/右dataframe合併的列名,也可為索引,陣列和列表。
left_index/right_index:是否以index作為資料合併的列名,True表示是。
sort:根據dataframe合併的keys排序,預設是。
suffixes:若有相同列且該列沒有作為合併的列,可通過suffixes設定該列的字尾名,一般為元組和列表型別。
整體效果,與SQL中的join操作類似,就是制定連線方式,按on的列進行join,然後以how的方式輸出DataFrame。
測試資料如下:
內連線
左連線
另外,外連線寫作outer,右連線寫作right ;和SQL的join效果簡直一模一樣。
join方法
join方法是基於index連線dataframe,merge方法是基於column連線,連線方法有內連線,外連線,左連線和右連線,與merge一致。
join和merge的連線方法類似,與merge很相似,直接用merge方法就ok了。
concat方法
concat方法是拼接函式,有行拼接和列拼接,預設是行拼接,拼接方法預設是外拼接(並集),拼接的物件是pandas資料型別。
series型別,行拼接和列拼接
注:也可在其中新增引數,join='inner' 預設是以並集的方式拼接的
dataframe型別,行拼接和列拼接
dataframe型別的行拼接
dataframe型別的列拼接
分組
size方法直接獲取分組後每組的大小
5. 函式應用與對映
- map() 將一個自定義函式應用於Series結構中的每個元素
- apply() 將一個函式作用於DataFrame中的每個行或者列
- applymap() 將函式做用於DataFrame中的所有元素
map()
map() 是一個Series的函式,將一個自定義函式應用於Series結構中的每個元素(elements),注意DataFrame結構中沒有map()
apply()
apply() 針對DataFrame在每行或者每列上執行計算 (支援維度變化: n==>1 返回Series 、 n ==>m 返回DataFrame)
基於上一步的df繼續操作:
apply中還可搭配邏輯判斷,或者value_counts()效果很佳
applymap()
applymap()
以下案例為向DataFrame中的每個元素新增‘!’結尾,以下兩種方式是等效的