本章主要學(xué)習(xí)的pandas的相關(guān)基礎(chǔ)雷激,如下圖
文件讀寫
讀取文件
使用一段代碼來進行演示
# 讀取csv文件
df_csv = pd.read_csv('../data/my_csv.csv')
# 讀取txt文件
df_txt = pd.read_table('../data/my_table.txt')
# 讀取excel文件
df_excel = pd.read_excel('../data/my_excel.xlsx')
# 如果不想將第一行當(dāng)作列名,可以使用header=None
df_excel = pd.read_excel('../data/my_excel.xlsx', header=None)
# index_col表示把某一列或幾列作為索引
pd.read_csv('../data/my_csv.csv', index_col=['col1', 'col2'])
文件寫入
一般在數(shù)據(jù)寫入中佛析,最常用的操作是把index設(shè)置為False痹仙,特別當(dāng)索引沒有特殊意義的時候闷游,這樣的行為能把索引在保存的時候去除拜姿。
df_csv.to_csv('../data/my_csv_saved.csv', index=False)
df_excel.to_excel('../data/my_excel_saved.xlsx', index=False)
pandas中沒有定義to_table函數(shù)烙样,但是to_csv可以保存為txt文件,并且允許自定義分隔符蕊肥,常用制表符\t分割:
df_txt.to_csv('../data/my_txt_saved.txt', sep='\t', index=False)
如果想要把表格快速轉(zhuǎn)換為markdown和latex語言谒获,可以使用to_markdown和to_latex函數(shù),此處需要安裝tabulate包。
df_csv.to_markdown()
df_csv.to_latex()
基本數(shù)據(jù)結(jié)構(gòu)
Pandas中定義了兩種基本的數(shù)據(jù)結(jié)構(gòu)批狱,Series和DataFrame
- Series
Series一般由四個部分組成裸准,分別是序列的值data、索引index赔硫、存儲類型dtype炒俱、序列的名字name。其中爪膊,索引也可以指定它的名字权悟,默認為空。這四個屬性可以通過以下的方式獲取
s = pd.Series(data = [100, 'a', {'dic1':5}],
index = pd.Index(['id1', 20, 'third'], name='my_idx'),
dtype = 'object',
name = 'my_name')
# data
s.value
# 獲取index
s.index
# 獲取dtype
s.dtype
# 獲取name
s.name
# 通過.shape可以獲取序列的長度
s.shape
其中object代表一種混合數(shù)據(jù)類型
- DataFrame
DataFrame在Series的基礎(chǔ)上增加了列索引惊完〗┣郏可以通過
[index_item]
獲取對應(yīng)的列的值
data = [[1, 'a', 1.2], [2, 'b', 2.2], [3, 'c', 3.2]]
df = pd.DataFrame(data = data,
index = ['row_%d'%i for i in range(3)],
columns=['col_0', 'col_1', 'col_2'])
# 獲取dataframe的值
df.value
# 獲取dataframe的index
df.index
# 獲取dataframe的column
df.columns
# 獲取dataframe的shape
df.shape
# 獲取指定的單列或多列
df['col_1'] #單列
df[['col_1', 'col_2']] #多列
# 對dataframe進行轉(zhuǎn)置
df.T
常用基本函數(shù)
匯總函數(shù)
head
小槐,tail
用于獲取表或者序列的前n行和后n行,n的默認值是5
info
荷辕,describe
返回表的信息概況和表中數(shù)值列對應(yīng)的主要統(tǒng)計量
在后面的章節(jié)中將會提高具有更高信息概括功能的pandas-profiling
包
df.head(5)
df.tail(5)
df.info()
df.describe()
特征統(tǒng)計函數(shù)
最常見的是sum, mean, median, var, std, max, min
"""以下函數(shù)均可通過axis參數(shù)指定操作的方向凿跳,默認是axis=0"""
df.sum()
df.mean()
df.median()
df.var()
df.std()
df.max()
df.min()
quantile, cout, idxmax, idxmin
返回的是分位數(shù), 非缺失值個數(shù)疮方, 最大值對應(yīng)的索引及最小值對應(yīng)的索引
唯一值函數(shù)
- 對序列使用
unique
和nunique
可以分別得到其唯一值組成的列表和唯一值的個數(shù)value_counts
可以得到唯一值和其對應(yīng)出現(xiàn)的頻數(shù):- 如果想要觀察多個列組合的唯一值控嗜,可以使用
drop_duplicates
。其中的關(guān)鍵參數(shù)是keep
骡显,默認值first
表示每個組合保留第一次出現(xiàn)的所在行疆栏,last
表示保留最后一次出現(xiàn)的所在行,False
表示把所有重復(fù)組合所在的行剔除duplicated
和drop_duplicates
的功能類似惫谤,但前者返回了是否為唯一值的布爾列表壁顶,其keep
參數(shù)與后者一致。其返回的序列溜歪,把重復(fù)元素設(shè)為True
若专,否則為False
。drop_duplicates
等價于把duplicated
為True
的對應(yīng)行剔除蝴猪。
替換函數(shù)(映射替換)
- 在
replace
中调衰,可以通過字典構(gòu)造,或者傳入兩個列表來進行替換replace
還有一種特殊的方向替換自阱,指定method
參數(shù)為ffill
則為用前面一個最近的未被替換的值進行替換嚎莉,bfill
則使用后面最近的未被替換的值進行替換
df['Gender'].replace({'Female':0, 'Male':1}).head()
s = pd.Series(['a', 1, 'b', 2, 1, 1, 'a'])
s.replace([1, 2], method='ffill')
s.replace([1, 2], method='bfill')
替換函數(shù)(邏輯替換)
邏輯替換包括了where
和mask
,這兩個函數(shù)是完全對稱的:where
函數(shù)在傳入條件為False
的對應(yīng)行進行替換沛豌,而mask
在傳入條件為True
的對應(yīng)行進行替換萝喘,當(dāng)不指定替換值時,替換為缺失值。clip
函數(shù)可以對超出范圍的值進行截斷
s = pd.Series([-1, 1.2345, 100, -50])
s.where(s<0)
s.where(s<0, 100)
s.mask(s<0)
s.mask(s<0, -50)
在 clip 中阁簸,超過邊界的只能截斷為邊界值爬早,如果要把超出邊界的替換為自定義的值,應(yīng)當(dāng)如何做启妹?
def my_clip(s:pd.Series, min_bound, max_bound, left_value, right_value)->pd.Series:
ret = s.clip(min_bound, max_bound)
ret = ret.mask(ret==min_bound, left_value)
ret = ret.mask(ret==max_bound, right_value)
return ret
排序函數(shù)
排序共有兩種方式筛严,其一為值排序,其二為索引排序饶米,對應(yīng)的函數(shù)是sort_values和sort_index
df_demo.sort_values(['Weight','Height'],ascending=[True,False]).head()
df_demo.sort_index(level=['Grade','Name'],ascending=[True,False]).head()
apply函數(shù)
6. apply方法
df_demo = df[['Height', 'Weight']]
def my_mean(x):
res = x.mean()
return res
df_demo.apply(my_mean)
apply
方法常用于DataFrame
的行迭代或者列迭代桨啃,它的axis
含義與第2小節(jié)中的統(tǒng)計聚合函數(shù)一致,apply
的參數(shù)往往是一個以序列為輸入的函數(shù)
窗口對象
pandas中有3類窗口檬输,分別是滑動窗口rolling照瘾、擴張窗口expanding以及指數(shù)加權(quán)窗口ewm
s = pd.Series([1,2,3,4,5])
roller = s.rolling(window = 3)
roller
rolling對象的默認窗口方向都是向前的,某些情況下用戶需要向后的窗口丧慈,例如對1,2,3設(shè)定向后窗口為2的sum操作析命,結(jié)果為3,5,NaN,此時應(yīng)該如何實現(xiàn)向后的滑窗操作逃默?(提示:使用shift)
s = pd.Series([1,2,3])
s = s.rolling(2)
s.sum().shift(-1)
cummax, cumsum, cumprod函數(shù)是典型的類擴張窗口函數(shù)鹃愤,請使用expanding對象依次實現(xiàn)它們。
import numpy as np
# cummax
s.expanding().max()
# cumsum
s.expanding().sum()
# cumprod
s.expanding().apply(lambda x:np.prod(x))
Ex1:口袋妖怪數(shù)據(jù)集
現(xiàn)有一份口袋妖怪的數(shù)據(jù)集完域,下面進行一些背景說明:
#
代表全國圖鑒編號软吐,不同行存在相同數(shù)字則表示為該妖怪的不同狀態(tài)妖怪具有單屬性和雙屬性兩種,對于單屬性的妖怪吟税,
Type 2
為缺失值Total, HP, Attack, Defense, Sp. Atk, Sp. Def, Speed
分別代表種族值凹耙、體力、物攻肠仪、防御肖抱、特攻、特防藤韵、速度虐沥,其中種族值為后6項之和
對
HP, Attack, Defense, Sp. Atk, Sp. Def, Speed
進行加總,驗證是否為Total
值泽艘。對于
#
重復(fù)的妖怪只保留第一條記錄欲险,解決以下問題:
- 求第一屬性的種類數(shù)量和前三多數(shù)量對應(yīng)的種類
- 求第一屬性和第二屬性的組合種類
- 求尚未出現(xiàn)過的屬性組合
- 按照下述要求,構(gòu)造
Series
:
- 取出物攻匹涮,超過120的替換為
high
天试,不足50的替換為low
,否則設(shè)為mid
- 取出第一屬性然低,分別用
replace
和apply
替換所有字母為大寫 - 求每個妖怪六項能力的離差喜每,即所有能力中偏離中位數(shù)最大的值务唐,添加到
df
并從大到小排序
# 驗證值之和是否與Total相等
df['add'] = df[['HP', 'Attack', 'Defense', 'Sp. Atk', 'Sp. Def', 'Speed']].sum(axis=1)
(df['add'] == df['Total']).all()
# 去除多余的記錄且只保留第一條記錄
unique_df = df.drop_duplicates(['#'], keep='first')
# Type 1的種類數(shù)量
print(unique_df['Type 1'].nunique())
# Type 1前三多數(shù)量對應(yīng)的種類
print(unique_df['Type 1'].value_counts().index[:3])
# 計算現(xiàn)在所有組合種類的數(shù)量
combine = unique_df.drop_duplicates(['Type 1', 'Type 2'])
num_unqiue_combine = combine.shape[0]
# 生成所有的組合
# 攻擊值替換
df['Attack'].mask(df['Attack']>120, 'high').mask(df['Attack']<50, 'low').mask((50<=df['Attack'])&(df['Attack']<=120), 'mid').head()
# 取出第一屬性
Type1 = df['Type 1']
# 使用replace進行大寫替換
# 構(gòu)造映射字典
map_dict = {}
for index in unique_df['Type 1'].value_counts().index:
map_dict[index] = index.upper()
Type1.replace(map_dict)
# 使用apply進行大寫替換
Type1.apply(lambda s: s.upper())
# 計算六項能力的離差
df['Deviation'] = df[['HP', 'Attack', 'Defense', 'Sp. Atk', 'Sp. Def', 'Speed']].apply(lambda x:np.max((x-x.median()).abs()), 1)
df.sort_values('Deviation', ascending=False).head()
# 源自答案
L_full = [' '.join([i, j]) if i!=j else i for j in dp_dup['Type 1'].unique() for i in dp_dup['Type 1'].unique()]
L_part = [' '.join([i, j]) if type(j)!=float else i for i, j in zip(attr_dup['Type 1'], attr_dup['Type 2'])]
res = set(L_full).difference(set(L_part))
len(res) #
Ex2:指數(shù)加權(quán)窗口
- 作為擴張窗口的
ewm
窗口
在擴張窗口中,用戶可以使用各類函數(shù)進行歷史的累計指標(biāo)統(tǒng)計带兜,但這些內(nèi)置的統(tǒng)計函數(shù)往往把窗口中的所有元素賦予了同樣的權(quán)重枫笛。事實上,可以給出不同的權(quán)重來賦給窗口中的元素刚照,指數(shù)加權(quán)窗口就是這樣一種特殊的擴張窗口刑巧。
其中,最重要的參數(shù)是alpha
无畔,它決定了默認情況下的窗口權(quán)重為啊楚,其中
表示當(dāng)前元素,
表示序列的第一個元素浑彰。
從權(quán)重公式可以看出恭理,離開當(dāng)前值越遠則權(quán)重越小,若記原序列為郭变,更新后的當(dāng)前元素為
颜价,此時通過加權(quán)公式歸一化后可知:
對于Series
而言,可以用ewm
對象如下計算指數(shù)平滑后的序列:
np.random.seed(0)
s = pd.Series(np.random.randint(-1,2,30).cumsum())
s.head()
使用expanding窗口實現(xiàn)
def ewm_func(x, alpha=0.2):
weight = np.array([(1 - alpha)**i for i in range(x.shape[0]-1, -1, -1)])
return (x * weight).sum() / weight.sum()
s.expanding().apply(ewm_func).head()
- 作為滑動窗口的
ewm
窗口(參考了答案)
從第1問中可以看到饵较,ewm
作為一種擴張窗口的特例拍嵌,只能從序列的第一個元素開始加權(quán)≡饴福現(xiàn)在希望給定一個限制窗口n
循诉,只對包含自身最近的n
個窗口進行滑動加權(quán)平滑。請根據(jù)滑窗函數(shù)撇他,給出新的wi
與yt
的更新公式茄猫,并通過rolling
窗口實現(xiàn)這一功能。
新的權(quán)重為困肩,
更新如下:
s.rolling(window=4).apply(ewm_func).head() # 無需對原函數(shù)改動