在數(shù)據(jù)分析和數(shù)據(jù)建模的過程中需要對(duì)數(shù)據(jù)進(jìn)行清洗和整理等工作,有時(shí)需要對(duì)數(shù)據(jù)增刪字段。下面為大家介紹Pandas對(duì)數(shù)據(jù)的復(fù)雜查詢、數(shù)據(jù)類型轉(zhuǎn)換、數(shù)據(jù)排序、數(shù)據(jù)的修改、數(shù)據(jù)迭代以及函數(shù)的使用
01、復(fù)雜查詢
實(shí)際業(yè)務(wù)需求往往需要按照一定的條件甚至復(fù)雜的組合條件來查詢數(shù)據(jù),接下來為大家介紹如何發(fā)揮Pandas數(shù)據(jù)篩選的無限可能,隨心所欲地取用數(shù)據(jù)。
1、邏輯運(yùn)算
# Q1成績大于36
df.Q1> 36
# Q1成績不小于60分,并且是C組成員
~(df.Q1< 60) & (df['team'] == 'C')
2、邏輯篩選數(shù)據(jù)
切片([ ])、.loc[ ]和.iloc[ ]均支持上文所介紹的邏輯表達(dá)式。
以下是切片([ ])的邏輯篩選示例:
df[df['Q1']== 8] # Q1等于8
df[~(df['Q1']== 8)] # 不等于8
df[df.name== 'Ben'] # 姓名為Ben
df[df.Q1> df.Q2]
以下是.loc[ ]和.lic[ ]示例:
# 表達(dá)式與切片一致
df.loc[df['Q1']> 90, 'Q1':] # Q1大于90,只顯示Q1
df.loc[(df.Q1> 80) & (df.Q2 < 15)] # and關(guān)系
df.loc[(df.Q1> 90) | (df.Q2 < 90)] # or關(guān)系
df.loc[df['Q1']== 8] # 等于8
df.loc[df.Q1== 8] # 等于8
df.loc[df['Q1']> 90, 'Q1':] # Q1大于90,顯示Q1及其后所有列
3、函數(shù)篩選
# 查詢最大索引的值
df.Q1[lambdas: max(s.index)] # 值為21
# 計(jì)算最大值
max(df.Q1.index)
# 99
df.Q1[df.index==99]
4、比較函數(shù)
# 以下相當(dāng)于 df[df.Q1 == 60]
df[df.Q1.eq(60)]
df.ne() # 不等于 !=
df.le() # 小于等于 <=
df.lt() # 小于 <
df.ge() # 大于等于 >=
df.gt() # 大于 >
5、查詢df.query()
df.query('Q1 > Q2 > 90') # 直接寫類型SQL where語句
還支持使用@符引入變量
# 支持傳入變量,如大于平均分40分的
a = df.Q1.mean()
df.query('Q1 > @a+40')
df.query('Q1 > `Q2`+@a')
df.eval()與df.query()類似,也可以用于表達(dá)式篩選。
# df.eval()用法與df.query類似
df[df.eval('Q1 > 90 > Q3 >10')]
df[df.eval('Q1 > `Q2`+@a')]
6、篩選df.filter()
df.filter(items=['Q1', 'Q2']) # 選擇兩列
df.filter(regex='Q', axis=1) # 列名包含Q的列
df.filter(regex='e$', axis=1) # 以e結(jié)尾的列
df.filter(regex='1$', axis=0) # 正則,索引名以1結(jié)尾
df.filter(like='2', axis=0) # 索引中有2的
# 索引中以2開頭、列名有Q的
df.filter(regex='^2',axis=0).filter(like='Q', axis=1)
7、按數(shù)據(jù)類型查詢
df.select_dtypes(include=['float64']) # 選擇float64型數(shù)據(jù)
df.select_dtypes(include='bool')
df.select_dtypes(include=['number']) # 只取數(shù)字型
df.select_dtypes(exclude=['int']) # 排除int類型
df.select_dtypes(exclude=['datetime64'])
02、數(shù)據(jù)類型轉(zhuǎn)換
在開始數(shù)據(jù)分析前,我們需要為數(shù)據(jù)分配好合適的類型,這樣才能夠高效地處理數(shù)據(jù)。不同的數(shù)據(jù)類型適用于不同的處理方法。
# 對(duì)所有字段指定統(tǒng)一類型
df = pd.DataFrame(data, dtype='float32')
# 對(duì)每個(gè)字段分別指定
df = pd.read_excel(data, dtype={'team':'string', 'Q1': 'int32'})
1、推斷類型
# 自動(dòng)轉(zhuǎn)換合適的數(shù)據(jù)類型
df.infer_objects() # 推斷后的DataFrame
df.infer_objects().dtypes
2、指定類型
# 按大體類型推定
m = ['1', 2, 3]
s = pd.to_numeric(s) # 轉(zhuǎn)成數(shù)字
pd.to_datetime(m) # 轉(zhuǎn)成時(shí)間
pd.to_timedelta(m) # 轉(zhuǎn)成時(shí)間差
pd.to_datetime(m, errors='coerce') # 錯(cuò)誤處理
pd.to_numeric(m, errors='ignore')
pd.to_numeric(m errors='coerce').fillna(0) # 兜底填充
pd.to_datetime(df[['year', 'month', 'day']])
# 組合成日期
3、類型轉(zhuǎn)換astype()
df.Q1.astype('int32').dtypes
# dtype('int32')
df.astype({'Q1': 'int32','Q2':'int32'}).dtypes
4、轉(zhuǎn)為時(shí)間類型
t = pd.Series(['20200801', '20200802'])
03、數(shù)據(jù)排序
數(shù)據(jù)排序是指按一定的順序?qū)?shù)據(jù)重新排列,幫助使用者發(fā)現(xiàn)數(shù)據(jù)的變化趨勢,同時(shí)提供一定的業(yè)務(wù)線索,還具有對(duì)數(shù)據(jù)糾錯(cuò)、分類等作用。
1、索引排序df.sort_index()
s.sort_index() # 升序排列
df.sort_index() # df也是按索引進(jìn)行排序
df.team.sort_index()s.sort_index(ascending=False)# 降序排列
s.sort_index(inplace=True) # 排序后生效,改變?cè)瓟?shù)據(jù)
# 索引重新0-(n-1)排,很有用,可以得到它的排序號(hào)
s.sort_index(ignore_index=True)
s.sort_index(na_position='first') # 空值在前,另'last'表示空值在后
s.sort_index(level=1) # 如果多層,排一級(jí)
s.sort_index(level=1, sort_remaining=False) #這層不排
# 行索引排序,表頭排序
df.sort_index(axis=1) # 會(huì)把列按列名順序排列
2、數(shù)值排序sort_values()
df.Q1.sort_values()
df.sort_values('Q4')
df.sort_values(by=['team', 'name'],ascending=[True, False])
其他方法:
s.sort_values(ascending=False) # 降序
s.sort_values(inplace=True) # 修改生效
s.sort_values(na_position='first') # 空值在前
# df按指定字段排列
df.sort_values(by=['team'])
df.sort_values('Q1')
# 按多個(gè)字段,先排team,在同team內(nèi)再看Q1
df.sort_values(by=['team', 'Q1'])
# 全降序
df.sort_values(by=['team', 'Q1'], ascending=False)
# 對(duì)應(yīng)指定team升Q1降
df.sort_values(by=['team', 'Q1'],ascending=[True, False])
# 索引重新0-(n-1)排
df.sort_values('team', ignore_index=True)
3、混合排序
df.set_index('name', inplace=True) # 設(shè)置name為索引
df.index.names = ['s_name'] # 給索引起名
df.sort_values(by=['s_name', 'team']) # 排序
4、按值大小排序nsmallest()和nlargest()
s.nsmallest(3) # 最小的3個(gè)
s.nlargest(3) # 最大的3個(gè)
# 指定列
df.nlargest(3, 'Q1')
df.nlargest(5, ['Q1', 'Q2'])
df.nsmallest(5, ['Q1', 'Q2'])
04、添加修改
數(shù)據(jù)的修改、增加和刪除在數(shù)據(jù)整理過程中時(shí)常發(fā)生。修改的情況一般是修改錯(cuò)誤、格式轉(zhuǎn)換,數(shù)據(jù)的類型修改等。
1、修改數(shù)值
df.iloc[0,0] # 查詢值
# 'Liver'
df.iloc[0,0] = 'Lily' # 修改值
df.iloc[0,0] # 查看結(jié)果
# 'Lily'
# 將小于60分的成績修改為60
df[df.Q1 < 60] = 60
# 查看
df.Q1
# 生成一個(gè)長度為100的列表
v = [1, 3, 5, 7, 9] * 20
2、替換數(shù)據(jù)
s.replace(0, 5) # 將列數(shù)據(jù)中的0換為5
df.replace(0, 5) # 將數(shù)據(jù)中的所有0換為5
df.replace([0, 1, 2, 3], 4) # 將0~3全換成4
df.replace([0, 1, 2, 3], [4, 3, 2, 1]) # 對(duì)應(yīng)修改
s.replace([1, 2], method='bfill') # 向下填充
df.replace({0: 10, 1: 100}) # 字典對(duì)應(yīng)修改
df.replace({'Q1': 0, 'Q2': 5}, 100) # 將指定字段的指定值修改為100
df.replace({'Q1': {0: 100, 4: 400}}) # 將指定列里的指定值替換為另一個(gè)指定的值
3、填充空值
df.fillna(0) # 將空值全修改為0
# {'backfill', 'bfill', 'pad', 'ffill',None}, 默認(rèn)為None
df.fillna(method='ffill') # 將空值都修改為其前一個(gè)值
values = {'A': 0, 'B': 1, 'C': 2, 'D': 3}
df.fillna(value=values) # 為各列填充不同的值
df.fillna(value=values, limit=1) # 只替換第一個(gè)
4、修改索引名
df.rename(columns={'team':'class'})
常用方法如下:
df.rename(columns={'Q1':'a', 'Q2': 'b'}) # 對(duì)表頭進(jìn)行修改
df.rename(index={0: 'x', 1:'y', 2: 'z'}) # 對(duì)索引進(jìn)行修改
df.rename(index=str) # 對(duì)類型進(jìn)行修改
df.rename(str.lower, axis='columns') # 傳索引類型
df.rename({1: 2, 2: 4}, axis='index')
# 對(duì)索引名進(jìn)行修改
s.rename_axis('animal')
df.rename_axis('animal') # 默認(rèn)是列索引
df.rename_axis('limbs',axis='columns') # 指定行索引
# 索引為多層索引時(shí)可以將type修改為class
df.rename_axis(index={'type': 'class'})
# 可以用set_axis進(jìn)行設(shè)置修改
s.set_axis(['a', 'b', 'c'], axis=0)
df.set_axis(['I', 'II'], axis='columns')
df.set_axis(['i', 'ii'], axis='columns',inplace=True)
5、增加列
df['foo'] = 100 # 增加一列foo,所有值都是100
df['foo'] = df.Q1 + df.Q2 # 新列為兩列相加
df['foo'] = df['Q1'] + df['Q2'] # 同上
# 把所有為數(shù)字的值加起來
df['total'] =df.select_dtypes(include=['int']).sum(1)df['total'] =
df.loc[:,'Q1':'Q4'].apply(lambda x: sum(x), axis='columns')
df.loc[:, 'Q10'] = '我是新來的' # 也可以
# 增加一列并賦值,不滿足條件的為NaN
df.loc[df.num >= 60, '成績'] = '合格'
df.loc[df.num < 60, '成績'] = '不合格'
6、插入列df.insert()
# 在第三列的位置上插入新列total列,值為每行的總成績
df.insert(2, 'total', df.sum(1))
7、指定列df.assign()
# 增加total列
df.assign(total=df.sum(1))
# 增加兩列
df.assign(total=df.sum(1), Q=100)
df.assign(total=df.sum(1)).assign(Q=100)
其他使用示例:
df.assign(Q5=[100]*100) # 新增加一列Q5
df = df.assign(Q5=[100]*100) # 賦值生效
df.assign(Q6=df.Q2/df.Q1) # 計(jì)算并增加Q6
df.assign(Q7=lambda d: d.Q1 * 9 / 5 + 32) # 使用lambda# 添加一列,值為表達(dá)式結(jié)果:True或False
df.assign(tag=df.Q1>df.Q2)
# 比較計(jì)算,True為1,F(xiàn)alse為0
df.assign(tag=(df.Q1>df.Q2).astype(int))
# 映射文案
df.assign(tag=(df.Q1>60).map({True:'及格',False:'不及格'}))
# 增加多個(gè)
df.assign(Q8=lambda d: d.Q1*5,
Q9=lambda d: d.Q8+1) # Q8沒有生效,不能直接用df.Q8
8、執(zhí)行表達(dá)式df.eval()
# 傳入求總分表達(dá)式
df.eval('total = Q1+Q3+Q3+Q4')
其他方法:
df['C1'] = df.eval('Q2 + Q3')
df.eval('C2 = Q2 + Q3') # 計(jì)算
a = df.Q1.mean()df.eval('C3 =`Q3`+@a') # 使用變量
df.eval('C3 = Q2 > (`Q3`+@a)') #加一個(gè)布爾值
df.eval('C4 = name + team', inplace=True) # 立即生效
9、增加行
# 新增索引為100的數(shù)據(jù)
df.loc[100] = ['tom', 'A', 88, 88, 88, 88]
其他方法:
df.loc[101]={'Q1':88,'Q2':99} # 指定列,無數(shù)據(jù)列值為NaN
df.loc[df.shape[0]+1] = {'Q1':88,'Q2':99} # 自動(dòng)增加索引
df.loc[len(df)+1] = {'Q1':88,'Q2':99}
# 批量操作,可以使用迭代
rows = [[1,2],[3,4],[5,6]]
for row in rows:
df.loc[len(df)] = row
10、追加合并
df = pd.DataFrame([[1, 2], [3, 4]],columns=list('AB'))
df2 = pd.DataFrame([[5, 6], [7, 8]],columns=list('AB'))
df.append(df2)
11、刪除
# 刪除索引為3的數(shù)據(jù)
s.pop(3)
# 93s
s
12、刪除空值
df.dropna() # 一行中有一個(gè)缺失值就刪除
df.dropna(axis='columns') # 只保留全有值的列
df.dropna(how='all') # 行或列全沒值才刪除
df.dropna(thresh=2) # 至少有兩個(gè)空值時(shí)才刪除
df.dropna(inplace=True) # 刪除并使替換生效
05、高級(jí)過濾
介紹幾個(gè)非常好用的復(fù)雜數(shù)據(jù)處理的數(shù)據(jù)過濾輸出方法。
1、df.where()
# 數(shù)值大于70
df.where(df > 70)
2、np.where()
# 小于60分為不及格
np.where(df>=60, '合格', '不合格')
3、df.mask()
# 符合條件的為NaN
df.mask(s > 80)
4、df.lookup()
# 行列相同數(shù)量,返回一個(gè)array
df.lookup([1,3,4], ['Q1','Q2','Q3']) # array([36, 96, 61])
df.lookup([1], ['Q1']) # array([36])
06、數(shù)據(jù)迭代
1、迭代Series
# 迭代指定的列
for i in df.name:
print(i)
# 迭代索引和指定的兩列
for i,n,q in zip(df.index, df.name,df.Q1):
print(i, n, q)
2、df.iterrows()
# 迭代,使用name、Q1數(shù)據(jù)
for index, row in df.iterrows():
print(index, row['name'], row.Q1)
3、df.itertuples()
for row in df.itertuples():
print(row)
4、df.items()
# Series取前三個(gè)
for label, ser in df.items():
print(label)
print(ser[:3], end='\n\n')
5、按列迭代
# 直接對(duì)DataFrame迭代
for column in df:
print(column)
07、函數(shù)應(yīng)用
1、pipe()
應(yīng)用在整個(gè)DataFrame或Series上。
# 對(duì)df多重應(yīng)用多個(gè)函數(shù)
f(g(h(df), arg1=a), arg2=b, arg3=c)
# 用pipe可以把它們連接起來
(df.pipe(h)
.pipe(g, arg1=a)
.pipe(f, arg2=b, arg3=c)
)
2、apply()
應(yīng)用在DataFrame的行或列中,默認(rèn)為列。
# 將name全部變?yōu)樾?br>df.name.apply(lambda x: x.lower())
3、applymap()
應(yīng)用在DataFrame的每個(gè)元素中。
# 計(jì)算數(shù)據(jù)的長度
def mylen(x):
return len(str(x))
df.applymap(lambda x:mylen(x)) # 應(yīng)用函數(shù)
df.applymap(mylen) # 效果同上
4、map()
應(yīng)用在Series或DataFrame的一列的每個(gè)元素中。
df.team.map({'A':'一班', 'B':'二班','C':'三班', 'D':'四班',})# 枚舉替換
df['name'].map(f)
5、agg()
# 每列的最大值
df.agg('max')
# 將所有列聚合產(chǎn)生sum和min兩行
df.agg(['sum', 'min'])
# 序列多個(gè)聚合
df.agg({'Q1' : ['sum', 'min'], 'Q2' : ['min','max']})
# 分組后聚合
df.groupby('team').agg('max')
df.Q1.agg(['sum', 'mean'])
6、transform()
df.transform(lambda x: x*2) # 應(yīng)用匿名函數(shù)
df.transform([np.sqrt, np.exp]) # 調(diào)用多個(gè)函數(shù)
7、copy()
s = pd.Series([1, 2], index=['a','b'])
s_1 = s
s_copy = s.copy()
s_1 is s # True
s_copy is s # False