文章目錄
- 系列文章
- 5 Pandas
- 5.1 Pandas介紹
- 5.2 Pandas資料結構
- 1 Series
- 創建Series
- Series屬性
- 2 DataFrame
- 創建DataFrame
- DataFrame屬性
- 重置索引
- 設定某列值為新索引
- 3 MultiIndex
- 5.3 基本資料操作
- 1 索引操作
- 直接操作
- loc和iloc
- 2 賦值操作
- 3 排序
- 5.4 運算
- 1 算數運算
- 2 邏輯運算
- 3 統計運算
- 4 自定義運算
- 5.5 畫圖
- 5.6 檔案讀取與存盤
- 1 CSV
- 2 HDF5
- 3 JSON
- 5.7 缺失值處理
- 5.8 資料離散化
- 1 資料離散化介紹
- 為什么要資料離散化
- 什么是資料離散化
- One-Hot編碼
- 2 API介紹
- 5.9 表格合并
- 5.10 交叉表與透視表
- 5.11 分組與聚合
- 5.12 練習案例-電影分析
- 1 獲取電影評分的平均分和導演人數
- 2 獲取電影評分和時長的分布情況
- 3 獲取電影分類情況
系列文章
機器學習入門 01 —— 機器學習概述
機器學習入門 02 —— 環境搭建(Jupyter Notebook 及擴展庫的安裝與使用)
機器學習入門 03 —— Matplotlib使用
機器學習入門 04 —— Numpy使用
機器學習入門 05 —— Pandas使用
機器學習入門 06 —— Seaborn使用
5 Pandas
學習目標:
-
了解Numpy與Pandas的不同
-
說明Pandas的Series與Dataframe兩種結構的區別
-
了解Pandas的MultiIndex結構
-
應用Pandas實作基本資料操作
-
應用Pandas實作資料的合并
-
應用crosstab和pivot_table實作交叉表與透視表
-
應用groupby和聚合函式實作資料的分組與聚合
-
了解Pandas的plot畫圖功能
-
應用Pandas實作資料的讀取和存盤
5.1 Pandas介紹
- 是專門用于資料挖掘的開源Python庫
- 以Numpy為基礎,利用了Numpy模塊在計算方面高性能的優勢
- 基于Matplotlib,能夠簡便快速地畫圖
- 有著獨特的資料結構
有了numpy和matplotlib,為什么還要使用Pandas?
-
讀取檔案方便
-
封裝了Matplotlib和Numpy的畫圖與計算
-
Pandas可以增強圖表可讀性:左邊是原生的資料顯示,右邊是用Pandas的顯示,
-
便捷的資料處理能力:Pandas可以顯示的資料長度更長
5.2 Pandas資料結構
Pandas中有三種資料結構:
- Series:對應一維陣列
- DataFrame:對應二維陣列
- MultiIndex(Panel):對應三維陣列
1 Series
Series是類似于一維陣列的資料結構,它能存盤任何型別的資料,Series由索引和資料構成,
創建Series
import pandas as pd
pd.Series(data=None, index=None, dtype=None)
data:傳入的資料,可以是ndarry、串列、字典、元祖等,
index:索引,要求是唯一值,且數量和data一一對應,如果沒有傳入索引,則默認從0開始,如果data是字典,索引就是key,
dtype:資料型別,
Series屬性
2 DataFrame
DataFrame類似于二維陣列,它就像一個表格,所以既有行索引又有列索引,
創建DataFrame
import pandas as pd
pd.DataFrame(data=None, index=None, columns=None)
index:行標簽,如果沒有傳入,則默認創建0-N作為索引,
columns:列標簽,如果沒有傳入,則默認創建0-N作為索引,
DataFrame屬性
重置索引
reset_index(drop=False)設定新的下標索引(0-N),drop如果為True表示要洗掉原來的索引值,
設定某列值為新索引
set_index(keys, drop=True)設定keys為新索引,drop默認為True,洗掉原索引,
上面把年份和月份都設定為索引,這其實就是一個MultiIndex(多重索引)
3 MultiIndex
MultiIndex是三維的資料結構,多重索引,其實就是在Series、DataFrame物件上擁有兩個或兩個以上的索引的結構,
我們列印下剛剛的年月份的索引:
創建MultiIndex
5.3 基本資料操作
為了更好的理解這些基本操作,這里的例子會先讀取一個真實的檔案資料,(關于檔案操作后面會介紹,這里看看就行)
# 讀取檔案(csv檔案其實就是Excel)
data = pd.read_csv('./stock_day.csv')
# 洗掉一些列,讓資料更簡單,再進行后面操作
data = data.drop(["ma5","ma10","ma20","v_ma5","v_ma10","v_ma20"], axis=1)
data.head(3)
1 索引操作
直接操作
要特別注意,Pandas直接操作索引是先列后行,和串列、Numpy的先行后列不同!!
# 直接使用列行操作(注意,是先列后行且不能切片,這和串列、Numpy的先行后列不同)
data['open']['2018-02-27'] # 獲取到 23.53
# 下面的用法是錯誤的
data['2018-02-27']['open'] # 不能先行后列
data[:1][:2] # 不能使用切片
loc和iloc
# 使用loc就是先行后列,還可以使用切片(注意,不能用[][],只能[: , :])
data.loc['2018-02-27':'2018-02-23','open':'close']
# 使用iloc也是先行后列,但用的是索引下標而不是索引值
data.iloc[:4, :3]
# loc和iloc混合使用(原理上還是一樣的)
# 第一個引數實質上還是傳遞索引值
data.loc[data.index[0:4], ['open', 'close', 'high', 'low']]
# 第二個引數實質上還是傳遞索引下標
data.iloc[0:4, data.columns.get_indexer(['open', 'close', 'high', 'low'])]
2 賦值操作
# 把'close'列全部賦值為1
data.close = 1 # 或者 data['close'] = 1
# 把'close'列 '2018-02-27'行 賦值為2
data.loc['2018-02-27', 'close'] = 2
# 把第4列大于23的賦值為0
data[data.iloc[:,3]>22]=0
data.head(3)
3 排序
Series和DataFrame都可以進行排序,根據索引排序,也可以根據值排序,
DataFrame排序
sort_values(by=keys,ascending=True):根據值排序,by是排序參考的鍵(可以多個),ascending為True是升序(默認),sort_index(ascending=True):根據索引排序,升序,
# 根據值排序,回傳一個新物件,不會改變原來物件; 根據'open'列,升序;
data.sort_values('open', ascending=True).head(3)
# 根據'open'列和'high'列,降序;(如果open相同才比較high)
data.sort_values(['open','high'], ascending=False).head(3)
# 根據索引 從小到大
data.sort_index().head(3)
Series排序
由于Series只有一列,所以不需要傳入引數,要么根據值排序要么根據索引排序,
sort_values(ascending=True):根據值排序,ascending=True升序(默認),sort_index(ascending=True):根據索引排序,
# 將DataFrame中某一列取出來就是Series
# 利用Series的值排序 升序
data['open'].sort_values(ascending=True).head(3)
# 利用Series的索引 降序
data['open'].sort_index(ascending=False).head(3)
5.4 運算
1 算數運算
# 加法 'open'列每個元素+10
data['open'].add(10) # 等價于 data['open']+10
# 減法 'open'
data['open'].sub(10)
# 乘法
data['open'].mul(10)
# 除法
data['open'].div(10)
2 邏輯運算
# 篩選 'open' > 23的資料
a = data['open'] > 23 # 每一行 會回傳True或False
data[a] # 獲取 'open' > 23的資料
# 多個邏輯運算子
data[(data['open'] > 23) & (data['open'] < 24) ]
# 使用邏輯運算子函式 query(運算式)
data.query('open > 23 & open < 24')
# 判斷 ‘open'列 有某個元素
b = data['open'].isin([23.53, 23.85]) # 會對每行的'open'進行判斷,回傳True或False
data[b] # 獲取'open'是23.53 或者 23.85的資料
3 統計運算
下面的函式可以對Series和DataFrame操作,對于DataFrame的統計函式,都有引數axis,axis=0表示對列進行統計(默認),axis=1表示對行進行統計,
| 統計函式 | 描述 |
|---|---|
| sum() | 求和 |
| mean() | 平均值 |
| median() | 中位數(是從小到大的中間一位數字) |
| min() | 最小值 |
| max() | 最大值 |
| mode() | 眾數(出現次數最多的) |
| abs() | 絕對值 |
| prod() | 標準差 |
| std() | 標準差 |
| var() | 方差 |
| idxmax() | 最大值的索引 |
| idxmin() | 最小值的索引 |
| cumsum() | 對某一列累計求和 |
| cummax() | 對某一列累計求最大值 |
| cummin() | 對某一列累計求最小值 |
| cumprod() | 對某一列累計求積 |
4 自定義運算
可以自己定義函式進行運算
'''
apply(function, axis=0)
function:自定義的函式;axis:0 對列,1對行,
'''
def function(x):
return x.max() - x.min()
# 舉例 下面定義一個佇列 求最大值與最小值的差值
# 等價于 data[['open', 'close']].apply(function)
data[['open', 'close']].apply(lambda x: x.max() - x.min())
5.5 畫圖
Pandas中封裝了Matplotlib的畫圖,所以用法大致相同,在Pandas中使用畫圖函式plot,同時,需要先匯入Matplotlib,
無論是DataFrame還是Series都是使用plot()畫圖,
DataFrame.plot(kind='line'):
- kind=‘line’,表示要畫折線圖(默認)
- kind=‘bar’,柱狀圖,加上引數stacked=True就是堆積柱狀圖
- kind=‘barh’,水平方向柱狀圖
- kind=‘hist’,直方圖
- kind=‘pie’,餅圖
- kind=‘scatter’,散點圖
下面舉個簡單例子:
import matplotlib.pyplot as pltimport pandas as pd# 讀取檔案data = pd.read_csv('./Pandas測驗資料.csv')# 洗掉一些列,讓資料更簡單,再進行后面操作data = data.drop(["ma5","ma10","ma20","v_ma5","v_ma10","v_ma20"], axis=1)# 排序data = data.sort_index()data = data['p_change'].cumsum()data.plot()plt.show() # 之所以要匯入matplotlib,是因為show()后才能顯示
5.6 檔案讀取與存盤
我們的資料大部分都存盤在檔案中,而Pandas支持多種檔案操作,例如CSV、HDF5、JSON、SQL、XLS等,
最常用的是HDF5和CSV,優先選擇HDF5:
- HDF5在存盤的時候支持壓縮,使用的方式是blosc,這個是速度最快的也是pandas默認支持的
- 使用壓縮可以提磁盤利用率,節省空間
- HDF5還是跨平臺的,可以輕松遷移到hadoop 上面
下面這張表是常用API
1 CSV
'''
讀取CSV
pandas.read_csv(filepath_or_buffer, sep=',', usecols)
filepath_or_buffer:檔案路徑
sep:分隔符,默認用,
usecols:指定讀取的列名(用串列型別)
'''
data = pd.read_csv('./Pandas測驗資料.csv', usecols=['open', 'close'])
'''
寫入csv
DataFrame.to_csv(path_or_buf=None, sep=',', columns=None, header=True, index=True, mode='w', encoding=None)
path_of_buf:檔案路徑
sep:分隔符
columns:要寫入的列索引
header:是否寫入【列索引】
index:是否寫入【行索引】
mode: 'w'重寫,'a'追加
encoding:編碼格式
'''
# 通常我們寫入檔案時,會把行索引也寫入進去,行索引會變成一列資料,所以我們可以用index=False不寫入行索引
data[:10].to_csv('test.csv', columns=['open'],index=False)
2 HDF5
'''
寫入HDF5
DataFrame.to_hdf(path_or_buf, key)
path_or_buffer:檔案路徑
key:讀取的鍵(HDF5的讀取和存盤都要指定一個key)
'''
data.to_hdf('hdf5_data.hdf', 'HDF5_DATA')
'''
讀取HDF5(讀取需要匯入tables模塊)
pandas.read_hdf(path_or_buf, key=None)
path_or_buffer:檔案路徑
key:讀取的鍵(HDF5的讀取和存盤都要指定一個key)
'''
data = pd.read_hdf('hdf5_data.hdf','HDF5_DATA')
3 JSON
JSON存盤形式有幾種:
- ‘split’:將索引、列名、資料三種分開,形如
{index -> [index], columns -> [columns], data -> [values]} - ’records’:形如
columns:values,通常用這種, - ‘index’:形如
index:{columns:values}... - ’columns’:形如
columns:{index:values} - ‘values’:直接輸出值
'''
JSON的存盤
DataFrame.to_json(path_or_buf=None, orient=None, lines=False)
path_or_buf:檔案路徑
orient:存盤JSON的形式 【'split'、'records','index','colummns','values'】
lines:一個物件存盤一行(建議設定為True)
'''
data.to_json('jsondata.json', orient='records')
'''
pandas.read_json(path_or_buf=None, orient=None, typ='frame', lines=False)
typ : default ‘frame’, 指定轉換成的物件型別series或者dataframe
'''
pd.read_json('jsondata.json',orient='records')
5.7 缺失值處理
我們獲取到的資料不一定都是完整的,可能某個資料有缺失,所以我們需要先對錯誤資料進行處理,
- 缺失的表現形式可能是
NaN或者?之類的,需要我們先查看資料進行判斷, - 如果缺失值的標記方式是
NaN- 用來判斷
NaN的函式:pd.isnull(DataFrame)、pd.notnull(DataFrame) - 存在缺失值:
- 如果缺失值數量少,則洗掉,數量多,則替換,
- 洗掉缺失值(不會改變原表,只回傳新表):
dropna(axis='rows)' - 替換缺失值:
fillna(value, inplace=True),其中value替換的值,inplace=True會修改原表,
- 用來判斷
- 如果缺失值不是
NaN而是?之類的- 先將
?替換為NaN(),再按上述方式處理,
- 先將
下面進行舉例說明:
- 判斷缺失值是否存在
- 洗掉缺失值NaN
- 替換缺失值NaN
- 對于
非NaN的缺失值,例如?:這是下面的鏈接
5.8 資料離散化
1 資料離散化介紹
為什么要資料離散化
連續資料離散化是為了簡化資料結構,資料離散化技術可以用來減少給定連續屬性值的個數,離散化方法經常作為資料挖掘的工具,
什么是資料離散化
就是在連續資料的值域上,將值域劃分為若干個離散的區間,最后用不同的符號或整數值代表落在每個子區間中的屬性值,下面舉個栗子:
- 原始人的身高資料:165,174,160,180,159,163,192,184
- 假設按照身高分幾個區間段:150~165, 165~180, 180~195
- 我們將資料分到了三個區間段,每個資料可以對應到矮、中、高三個類別的區間,最終要處理成一個"啞變數"矩陣(后面有解釋)
One-Hot編碼
在很多學習任務中,特征并不總是連續值,而有可能是分類值,
離散特征的編碼分為兩種情況:
1、離散特征的取值之間沒有大小的意義,比如color:[red,blue],那么就使用one-hot編碼
2、離散特征的取值有大小的意義,比如size:[X,XL,XXL],那么就使用數值的映射{X:1,XL:2,XXL:3}
One-Hot編碼又稱為獨熱編碼(或啞變數 dummy variable),我們把資料離散化后的每個類別區間轉為布爾列,這些列中只有一個可以為True(1),例如下面這種表格,把【Human、Penguin、Octopus、Alien】分為了四個布爾列,
2 API介紹
pd.qcut(data, q):回傳Series,對資料進行分組(區間是自動分配的),q是分組個數,通常會再搭配value_counts()用來統計每組里資料個數,pd.cut(data, bins):回傳Series,也是對資料分組,但區間由自己指定,bins是分組區間,pd.get_dummines(data, prefix=None):data是Series或者DataFrame,prefix是分組的名稱,
下面舉例:
# 讀取CSV資料(某日股票資料)
data = pd.read_csv('stock_day.csv')
p_change = data['p_change']
qcut = pd.qcut(p_change, 10) # 將p_change分10組
qcut.value_counts() # 查看每組的資料個數
bins = [-100, -7, -5, -3, 0, 3, 5, 7, 100]
cut = pd.cut(p_change, bins) # 將p_change按bins分組
cut.value_counts() # 查看每組的資料個數
# 查看熱編碼
pd.get_dummies(cut).head()
5.9 表格合并
有時候我們會想講多張表格合并在一起,就需要用到pd.concat()或者pd.merge()
pd.concat([data1, data2], axis=1),第一個引數是表格資料的串列,第二個引數為1則按行索引合并,為0則按列索引合并,
# 將剛剛的One-Hot編碼與原資料合并
data = pd.read_csv('stock_day.csv')
bins = [-100, -7, -5, -3, 0, 3, 5, 7, 100]
cut = pd.cut(p_change, bins)
dummies = pd.get_dummies(cut, prefix='rise')
pd.concat([data, dummies], axis=1) # 按行索引
pd.merge(left, right, how='inner', on=None)- 可以指定安裝兩組資料的共同鍵值對合并或按照左右各自合并,
- left:左表(DataFrame)
- right:右表(DataFrame)
- on:指定共同的鍵(如果不指定就是左右表各自合并)
- how:按什么方式連接(和資料庫的表連接類似,inner、left、right、outer)
left = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
'B': ['B0', 'B1', 'B2', 'B3'],
'key1': ['K0', 'K0', 'K1', 'K2'],
'key2': ['K0', 'K1', 'K0', 'K1']})
right = pd.DataFrame({'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3'],
'key1': ['K0', 'K1', 'K1', 'K2'],
'key2': ['K0', 'K0', 'K0', 'K0']})
內連接:
# 默認用內連接 inner,使用兩個表共同鍵作為連接點
pd.merge(left, right) # 可以不指定on=['key1', 'key2']
左連接:
# 左連接
pd.merge(left, right, how='left', on=['key1', 'key2'])
右連接:
# 右連接
pd.merge(left, right, how='right', on=['key1', 'key2'])
外連接:
# 外連接
pd.merge(left, right, how='outer', on=['key1', 'key2'])
5.10 交叉表與透視表
交叉表:用于統計兩列資料之間的關系,
透視表:是將原有的DataFrame的列分別作為行索引和列索引,然后對指定的列應用聚集函式【pd.crosstab(列1,列2)】
下面用案例進行說明:探究股票漲跌與星期之間的關系(交叉表),【data.pivot_table([列1..], 索引)】
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# 讀取股票資料 (索引是 '2018-02-27')
data = pd.read_csv('stock_day.csv')
# 將行索引轉換為datatime型別,再將日期轉換為對應的星期幾,
week = pd.to_datetime(data.index).weekday
# 增加一個新列 星期
data['week'] = week
# 判斷漲跌 p_change列,大于0則置為1(漲),小于0則置為0(跌),并將結果作為新列p_n
data['p_n'] = np.where(data['p_change'] > 0, 1, 0)
# 交叉表:此時得到的是 0 和 1 的統計數量,(即漲跌)———— 看圖1
count = pd.crosstab(data['week'], data['p_n'])
# 現在將上面的表轉為百分比[例如 63/(63+62)] ———— 看圖2
img = count.div(count.sum(axis=1).astype(np.float32), axis=0)
# 繪圖 ———— 看圖3
img.plot(kind='bar', stacked=True)
plt.show()
圖1:
圖2:
圖3:
從上面可看出,交叉表是統計出兩列的數量關系,而透視表是直接得出百分比關系,
data.pivot_table(['p_n'], 'week')
5.11 分組與聚合
分組與聚合通常是分析資料的一種方式,通常與一些統計函式一起使用,查看資料的分組情況,其實剛才的交叉表與透視表也有分組的功能,所以算是分組的一種形式,只不過他們主要是計算次數或者計算比例,下面這張圖就非常形象,
聚合的內置函式:sum(), mean(), max(), min(), count(), size(), describe()
下面用代碼演示:
星巴克案例:
# 讀取資料 (資料來自Kaggle)
starbucks = pd.read_csv("directory.csv")
# 按國家分組,并求出每個國家星巴克零售店的數量
count = starbucks.groupby(['Country']).count()
# 繪圖顯示
count['Brand'].pl ot(kind='bar', figsize=(20, 8))
plt.show()
# 對國家和省份進行分組
starbucks.groupby(['Country', 'State/Province']).count().head()
5.12 練習案例-電影分析
現在對2006年至2016年1000部流行電影進行分析:
- 獲取電影評分的平均分和導演人數
- 獲取電影評分和時長的分布情況
- 獲取電影分類情況
先導包并讀取電影資料,
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
movie = pd.read_csv('IMDB-Movie-Data.csv')
movie.head(3)

1 獲取電影評分的平均分和導演人數
# 平均分
movie['Rating'].mean()
# 導演人數
movie['Director'].unique().shape[0] # 方法一 unique()是去除重復元素
np.unique(movie['Director']).shape[0] # 方法二
2 獲取電影評分和時長的分布情況
如果使用Pandas直接繪制直方圖,會出現坐標無法對齊的問題,所以還是要使用Matplotlib,
# 如果使用Pandas繪制直方圖,會出現坐標無法對齊的問題
movie['Rating'].plot(kind='hist', figsize=(14, 6))
# 1. 創建畫布
plt.figure(figsize=(20,8),dpi=80)
# 2. 繪制影像
plt.hist(movie["Rating"].values,bins=20) # 分為20組(即間隔)
# 2.1 創建刻度表(否則還是會有無法對齊的問題)
max_rating = movie['Rating'].max()
min_rating = movie['Rating'].min()
x_tick = np.linspace(min_rating, max_rating, num=21) # 均分為21個數字,中間就有20個間隔
plt.xticks(x_tick)
# 2.2 添加網格
plt.grid()
# 3. 顯示影像
plt.show()
3 獲取電影分類情況
思路:
- 創建一個全為0的表(即DataFrame),表的列索引就是電影類別(要去重)
- 然后遍歷所有電影,由于每部電影可能有多個類別,所以在遍歷一部電影時,根據其類別使其列值加1
- 對每一列求和,這樣就得到每個類別的電影總數
# 1. 先判斷總共有哪些電影類別,要去重,每部電影的多個類別用 , 分割
temp_list = [i.split(',') for i in movie['Genre']] # 將每部電影的類別分割,并放入串列,
genre_list = np.unique([i for j in temp_list for i in j]) # 獲取到總的電影類別串列,
# 2. 以電影類別作為列索引,創建全為0的DataFrame
temp_df = pd.DataFrame(np.zeros([movie.shape[0], genre_list.shape[0]]), columns=genre_list)
# 3. 遍歷每部電影,并根據每部電影的類別 使其對于列加1
for i in range(movie.shape[0]):
# 其中 temp_list[0] = ['Action', 'Adventure', 'Sci-Fi']
# 所以這行代碼是讓每部電影對應類別的列值 +1
temp_df.loc[i, temp_list[i]] = 1
# 4. 每列求和并從小到大排序
result = temp_df.sum().sort_values()
# 5. 繪圖
result.plot(kind='bar', figsize=(15, 6), fontsize=20, colormap='cool')
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/292960.html
標籤:python
