基礎(chǔ)部分
導(dǎo)入 Pandas:
import pandas as pd
查看 Pandas 版本信息:
print(pd.__version__)
Pandas 的數(shù)據(jù)結(jié)構(gòu):Pandas 主要有 Series(一維數(shù)組)芥吟,DataFrame(二維數(shù)組),Panel(三維數(shù)組)硕糊,Panel4D(四維數(shù)組)爽撒,PanelND(更多維數(shù)組)等數(shù)據(jù)結(jié)構(gòu)。其中 Series 和 DataFrame 應(yīng)用的最為廣泛归敬。
Series 是一維帶標(biāo)簽的數(shù)組酷含,它可以包含任何數(shù)據(jù)類型。包括整數(shù)汪茧,字符串椅亚,浮點(diǎn)數(shù),Python 對(duì)象等舱污。Series 可以通過(guò)標(biāo)簽來(lái)定位呀舔。
DataFrame 是二維的帶標(biāo)簽的數(shù)據(jù)結(jié)構(gòu)。我們可以通過(guò)標(biāo)簽來(lái)定位數(shù)據(jù)扩灯。這是 NumPy 所沒(méi)有的媚赖。
創(chuàng)建 Series 數(shù)據(jù)類型
Pandas 中霜瘪,Series 可以被看作由 1 列數(shù)據(jù)組成的數(shù)據(jù)集。
創(chuàng)建 Series 語(yǔ)法:s = pd.Series(data, index=index)惧磺,可以通過(guò)多種方式進(jìn)行創(chuàng)建颖对,以下介紹了 3 個(gè)常用方法。
從列表創(chuàng)建 Series:
arr = [0, 1, 2, 3, 4]
s1 = pd.Series(arr) # 如果不指定索引磨隘,則默認(rèn)從 0 開(kāi)始
s1
從 Ndarray 創(chuàng)建 Series:
import numpy as np
n = np.random.randn(5) # 創(chuàng)建一個(gè)隨機(jī) Ndarray 數(shù)組
index = ['a', 'b', 'c', 'd', 'e']
s2 = pd.Series(n, index=index)
s2
從字典創(chuàng)建 Series:
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} # 定義示例字典
s3 = pd.Series(d)
s3
Series 基本操作
修改 Series 索引:
print(s1) # 以 s1 為例
s1.index = ['A', 'B', 'C', 'D', 'E'] # 修改后的索引
s1
Series 縱向拼接:
s4 = s3.append(s1) # 將 s1 拼接到 s3
s4
Series 按指定索引刪除元素:
print(s4)
s4 = s4.drop('e') # 刪除索引為 e 的值
s4
Series 修改指定索引元素:
s4['A'] = 6 # 修改索引為 A 的值 = 6
s4
Series 按指定索引查找元素:
s4['B']
Series 切片操作:
s4[:3]
Series 運(yùn)算
Series 加法運(yùn)算:
Series 的加法運(yùn)算是按照索引計(jì)算缤底,如果索引不同則填充為 NaN(空值)。
s4.add(s3)
Series 減法運(yùn)算:
Series的減法運(yùn)算是按照索引對(duì)應(yīng)計(jì)算琳拭,如果不同則填充為 NaN(空值)训堆。
s4.sub(s3)
Series 乘法運(yùn)算:
Series 的乘法運(yùn)算是按照索引對(duì)應(yīng)計(jì)算,如果索引不同則填充為 NaN(空值)白嘁。
s4.mul(s3)
Series 除法運(yùn)算:
Series 的除法運(yùn)算是按照索引對(duì)應(yīng)計(jì)算坑鱼,如果索引不同則填充為 NaN(空值)。
s4.div(s3)
Series 求中位數(shù):
s4.median()
Series 求和:
s4.sum()
Series 求最大值:
s4.max()
Series 求最小值:
s4.min()
創(chuàng)建 DataFrame 數(shù)據(jù)類型
與 Sereis 不同絮缅,DataFrame 可以存在多列數(shù)據(jù)鲁沥。一般情況下,DataFrame 也更加常用耕魄。
通過(guò) NumPy 數(shù)組創(chuàng)建 DataFrame:
dates = pd.date_range('today', periods=6) # 定義時(shí)間序列作為 index
num_arr = np.random.randn(6, 4) # 傳入 numpy 隨機(jī)數(shù)組
columns = ['A', 'B', 'C', 'D'] # 將列表作為列名
df1 = pd.DataFrame(num_arr, index=dates, columns=columns)
df1
通過(guò)字典數(shù)組創(chuàng)建 DataFrame:
data = {'animal': ['cat', 'cat', 'snake', 'dog', 'dog', 'cat', 'snake', 'cat', 'dog', 'dog'],
'age': [2.5, 3, 0.5, np.nan, 5, 2, 4.5, np.nan, 7, 3],
'visits': [1, 3, 2, 3, 2, 3, 1, 1, 2, 1],
'priority': ['yes', 'yes', 'no', 'yes', 'no', 'no', 'no', 'yes', 'no', 'no']}
labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
df2 = pd.DataFrame(data, index=labels)
df2
查看 DataFrame 的數(shù)據(jù)類型:
df2.dtypes
DataFrame 基本操作
預(yù)覽 DataFrame 的前 5 行數(shù)據(jù):
df2.head() # 默認(rèn)為顯示 5 行画恰,可根據(jù)需要在括號(hào)中填入希望預(yù)覽的行數(shù)
查看 DataFrame 的后 3 行數(shù)據(jù):
df2.tail(3)
查看 DataFrame 的索引:
df2.index
查看 DataFrame 的列名:
df2.columns
查看 DataFrame 的數(shù)值:
df2.values
查看 DataFrame 的統(tǒng)計(jì)數(shù)據(jù):
df2.describe()
DataFrame 轉(zhuǎn)置操作:
df2.T
對(duì) DataFrame 進(jìn)行按列排序:
df2.sort_values(by='age') # 按 age 升序排列
對(duì) DataFrame 數(shù)據(jù)切片:
df2[1:3]
對(duì) DataFrame 通過(guò)標(biāo)簽查詢(單列):
df2['age']
對(duì) DataFrame 通過(guò)標(biāo)簽查詢(多列):
df2[['age', 'animal']] # 傳入一個(gè)列名組成的列表
對(duì) DataFrame 通過(guò)位置查詢:
df2.iloc[1:3] # 查詢 2,3 行
DataFrame 副本拷貝:
# 生成 DataFrame 副本吸奴,方便數(shù)據(jù)集被多個(gè)不同流程使用
df3 = df2.copy()
df3
判斷 DataFrame 元素是否為空:
df3.isnull() # 如果為空則返回為 True
添加列數(shù)據(jù):
num = pd.Series([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], index=df3.index)
df3['No.'] = num # 添加以 'No.' 為列名的新數(shù)據(jù)列
df3
根據(jù) DataFrame 的下標(biāo)值進(jìn)行更改允扇。:
# 修改第 2 行與第 2 列對(duì)應(yīng)的值 3.0 → 2.0
df3.iat[1, 1] = 2 # 索引序號(hào)從 0 開(kāi)始,這里為 1, 1
df3
根據(jù) DataFrame 的標(biāo)簽對(duì)數(shù)據(jù)進(jìn)行修改:
df3.loc['f', 'age'] = 1.5
df3
DataFrame 求平均值操作:
df3.mean()
對(duì) DataFrame 中任意列做求和操作:
df3['visits'].sum()
字符串操作
將字符串轉(zhuǎn)化為小寫(xiě)字母:
string = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca',
np.nan, 'CABA', 'dog', 'cat'])
print(string)
string.str.lower()
將字符串轉(zhuǎn)化為大寫(xiě)字母:
string.str.upper()
DataFrame 缺失值操作
對(duì)缺失值進(jìn)行填充:
df4 = df3.copy()
print(df4)
df4.fillna(value=3)
刪除存在缺失值的行:
df5 = df3.copy()
print(df5)
df5.dropna(how='any') # 任何存在 NaN 的行都將被刪除
DataFrame 按指定列對(duì)齊:
left = pd.DataFrame({'key': ['foo1', 'foo2'], 'one': [1, 2]})
right = pd.DataFrame({'key': ['foo2', 'foo3'], 'two': [4, 5]})
print(left)
print(right)
# 按照 key 列對(duì)齊連接则奥,只存在 foo2 相同考润,所以最后變成一行
pd.merge(left, right, on='key')
DataFrame 文件操作
CSV 文件寫(xiě)入:
df3.to_csv('animal.csv')
print("寫(xiě)入成功.")
CSV 文件讀取:
df_animal = pd.read_csv('animal.csv')
df_animal
Excel 寫(xiě)入操作:
df3.to_excel('animal.xlsx', sheet_name='Sheet1')
print("寫(xiě)入成功.")
Excel 讀取操作:
pd.read_excel('animal.xlsx', 'Sheet1', index_col=None, na_values=['NA'])
進(jìn)階部分
時(shí)間序列索引
建立一個(gè)以 2018 年每一天為索引读处,值為隨機(jī)數(shù)的 Series:
dti = pd.date_range(start='2018-01-01', end='2018-12-31', freq='D')
s = pd.Series(np.random.rand(len(dti)), index=dti)
s
統(tǒng)計(jì)s 中每一個(gè)周三對(duì)應(yīng)值的和:
# 周一從 0 開(kāi)始
s[s.index.weekday == 2].sum()
統(tǒng)計(jì)s中每個(gè)月值的平均值:
s.resample('M').mean()
將 Series 中的時(shí)間進(jìn)行轉(zhuǎn)換(秒轉(zhuǎn)分鐘):
s = pd.date_range('today', periods=100, freq='S')
ts = pd.Series(np.random.randint(0, 500, len(s)), index=s)
ts.resample('Min').sum()
UTC 世界時(shí)間標(biāo)準(zhǔn):
s = pd.date_range('today', periods=1, freq='D') # 獲取當(dāng)前時(shí)間
ts = pd.Series(np.random.randn(len(s)), s) # 隨機(jī)數(shù)值
ts_utc = ts.tz_localize('UTC') # 轉(zhuǎn)換為 UTC 時(shí)間
ts_utc
轉(zhuǎn)換為上海所在時(shí)區(qū):
ts_utc.tz_convert('Asia/Shanghai')
不同時(shí)間表示方式的轉(zhuǎn)換:
rng = pd.date_range('1/1/2018', periods=5, freq='M')
ts = pd.Series(np.random.randn(len(rng)), index=rng)
print(ts)
ps = ts.to_period()
print(ps)
ps.to_timestamp()
Series 多重索引
創(chuàng)建多重索引 Series:
構(gòu)建一個(gè) letters = ['A', 'B', 'C'] 和 numbers = list(range(10))為索引糊治,值為隨機(jī)數(shù)的多重索引 Series。
letters = ['A', 'B', 'C']
numbers = list(range(10))
mi = pd.MultiIndex.from_product([letters, numbers]) # 設(shè)置多重索引
s = pd.Series(np.random.rand(30), index=mi) # 隨機(jī)數(shù)
s
多重索引 Series 查詢:
# 查詢索引為 1罚舱,3井辜,6 的值
s.loc[:, [1, 3, 6]]
多重索引 Series 切片:
s.loc[pd.IndexSlice[:'B', 5:]]
DataFrame 多重索引
根據(jù)多重索引創(chuàng)建 DataFrame:
創(chuàng)建一個(gè)以 letters = ['A', 'B'] 和 numbers = list(range(6))為索引,值為隨機(jī)數(shù)據(jù)的多重索引 DataFrame管闷。
frame = pd.DataFrame(np.arange(12).reshape(6, 2),
index=[list('AAABBB'), list('123123')],
columns=['hello', 'shiyanlou'])
frame
多重索引設(shè)置列名稱:
frame.index.names = ['first', 'second']
frame
DataFrame 多重索引分組求和:
frame.groupby('first').sum()
DataFrame 行列名稱轉(zhuǎn)換:
print(frame)
frame.stack()
DataFrame 索引轉(zhuǎn)換:
print(frame)
frame.unstack()
DataFrame 條件查找:
# 示例數(shù)據(jù)
data = {'animal': ['cat', 'cat', 'snake', 'dog', 'dog', 'cat', 'snake', 'cat', 'dog', 'dog'],
'age': [2.5, 3, 0.5, np.nan, 5, 2, 4.5, np.nan, 7, 3],
'visits': [1, 3, 2, 3, 2, 3, 1, 1, 2, 1],
'priority': ['yes', 'yes', 'no', 'yes', 'no', 'no', 'no', 'yes', 'no', 'no']}
labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
df = pd.DataFrame(data, index=labels)
查找 age 大于 3 的全部信息
df[df['age'] > 3]
** 根據(jù)行列索引切片:**
df.iloc[2:4, 1:3]
DataFrame 多重條件查詢:
查找 age<3 且為 cat 的全部數(shù)據(jù)粥脚。
df = pd.DataFrame(data, index=labels)
df[(df['animal'] == 'cat') & (df['age'] < 3)]
DataFrame 按關(guān)鍵字查詢:
df3[df3['animal'].isin(['cat', 'dog'])]
DataFrame 按標(biāo)簽及列名查詢。:
df.loc[df2.index[[3, 4, 8]], ['animal', 'age']]
DataFrame 多條件排序:
按照 age 降序渐北,visits 升序排列
df.sort_values(by=['age', 'visits'], ascending=[False, True])
DataFrame 多值替換:
將 priority 列的 yes 值替換為 True阿逃,no 值替換為 False。
df['priority'].map({'yes': True, 'no': False})
DataFrame 分組求和:
df4.groupby('animal').sum()
使用列表拼接多個(gè) DataFrame:
temp_df1 = pd.DataFrame(np.random.randn(5, 4)) # 生成由隨機(jī)數(shù)組成的 DataFrame 1
temp_df2 = pd.DataFrame(np.random.randn(5, 4)) # 生成由隨機(jī)數(shù)組成的 DataFrame 2
temp_df3 = pd.DataFrame(np.random.randn(5, 4)) # 生成由隨機(jī)數(shù)組成的 DataFrame 3
print(temp_df1)
print(temp_df2)
print(temp_df3)
pieces = [temp_df1, temp_df2, temp_df3]
pd.concat(pieces)
找出 DataFrame 表中和最小的列:
df = pd.DataFrame(np.random.random(size=(5, 10)), columns=list('abcdefghij'))
print(df)
df.sum().idxmin() # idxmax(), idxmin() 為 Series 函數(shù)返回最大最小值的索引值
DataFrame 中每個(gè)元素減去每一行的平均值:
df = pd.DataFrame(np.random.random(size=(5, 3)))
print(df)
df.sub(df.mean(axis=1), axis=0)
DataFrame 分組,并得到每一組中最大三個(gè)數(shù)之和:
df = pd.DataFrame({'A': list('aaabbcaabcccbbc'),
'B': [12, 345, 3, 1, 45, 14, 4, 52, 54, 23, 235, 21, 57, 3, 87]})
print(df)
df.groupby('A')['B'].nlargest(3).sum(level=0)
透視表
當(dāng)分析龐大的數(shù)據(jù)時(shí)恃锉,為了更好的發(fā)掘數(shù)據(jù)特征之間的關(guān)系杉女,且不破壞原數(shù)據(jù)横腿,就可以利用透視表 pivot_table 進(jìn)行操作。
透視表的創(chuàng)建:
新建表將 A, B, C 列作為索引進(jìn)行聚合。
df = pd.DataFrame({'A': ['one', 'one', 'two', 'three'] * 3,
'B': ['A', 'B', 'C'] * 4,
'C': ['foo', 'foo', 'foo', 'bar', 'bar', 'bar'] * 2,
'D': np.random.randn(12),
'E': np.random.randn(12)})
print(df)
pd.pivot_table(df, index=['A', 'B'])
透視表按指定行進(jìn)行聚合:
將該 DataFrame 的 D 列聚合调窍,按照 A,B 列為索引進(jìn)行聚合瘪松,聚合的方式為默認(rèn)求均值乏悄。
pd.pivot_table(df, values=['D'], index=['A', 'B'])
透視表聚合方式定義:
上一題中 D 列聚合時(shí)氮凝,采用默認(rèn)求均值的方法,若想使用更多的方式可以在 aggfunc 中實(shí)現(xiàn)萝映。
pd.pivot_table(df, values=['D'], index=['A', 'B'], aggfunc=[np.sum, len])
透視表利用額外列進(jìn)行輔助分割:
D 列按照 A,B 列進(jìn)行聚合時(shí)吴叶,若關(guān)心 C 列對(duì) D 列的影響,可以加入 columns 值進(jìn)行分析序臂。
pd.pivot_table(df, values=['D'], index=['A', 'B'],
columns=['C'], aggfunc=np.sum)
透視表的缺省值處理:
在透視表中由于不同的聚合方式蚌卤,相應(yīng)缺少的組合將為缺省值,可以加入 fill_value 對(duì)缺省值處理奥秆。
pd.pivot_table(df, values=['D'], index=['A', 'B'],
columns=['C'], aggfunc=np.sum, fill_value=0)
絕對(duì)類型
在數(shù)據(jù)的形式上主要包括數(shù)量型和性質(zhì)型逊彭,數(shù)量型表示著數(shù)據(jù)可數(shù)范圍可變,而性質(zhì)型表示范圍已經(jīng)確定不可改變构订,絕對(duì)型數(shù)據(jù)就是性質(zhì)型數(shù)據(jù)的一種侮叮。
絕對(duì)型數(shù)據(jù)定義:
df = pd.DataFrame({"id": [1, 2, 3, 4, 5, 6], "raw_grade": [
'a', 'b', 'b', 'a', 'a', 'e']})
df["grade"] = df["raw_grade"].astype("category")
df
對(duì)絕對(duì)型數(shù)據(jù)重命名:
df["grade"].cat.categories = ["very good", "good", "very bad"]
df
重新排列絕對(duì)型數(shù)據(jù)并補(bǔ)充相應(yīng)的缺省值:
df["grade"] = df["grade"].cat.set_categories(
["very bad", "bad", "medium", "good", "very good"])
df
對(duì)絕對(duì)型數(shù)據(jù)進(jìn)行排序:
df.sort_values(by="grade")
對(duì)絕對(duì)型數(shù)據(jù)進(jìn)行分組:
df.groupby("grade").size()
數(shù)據(jù)清洗
缺失值擬合:
在FilghtNumber中有數(shù)值缺失,其中數(shù)值為按 10 增長(zhǎng)悼瘾,補(bǔ)充相應(yīng)的缺省值使得數(shù)據(jù)完整囊榜,并讓數(shù)據(jù)為 int 類型。
df = pd.DataFrame({'From_To': ['LoNDon_paris', 'MAdrid_miLAN', 'londON_StockhOlm',
'Budapest_PaRis', 'Brussels_londOn'],
'FlightNumber': [10045, np.nan, 10065, np.nan, 10085],
'RecentDelays': [[23, 47], [], [24, 43, 87], [13], [67, 32]],
'Airline': ['KLM(!)', '<Air France> (12)', '(British Airways. )',
'12. Air France', '"Swiss Air"']})
df['FlightNumber'] = df['FlightNumber'].interpolate().astype(int)
df
數(shù)據(jù)列拆分:
其中From_to應(yīng)該為兩獨(dú)立的兩列From和To亥宿,將From_to依照_拆分為獨(dú)立兩列建立為一個(gè)新表锦聊。
temp = df.From_To.str.split('_', expand=True)
temp.columns = ['From', 'To']
temp
字符標(biāo)準(zhǔn)化:
地點(diǎn)的名字都不規(guī)范(如:londON應(yīng)該為L(zhǎng)ondon)需要對(duì)數(shù)據(jù)進(jìn)行標(biāo)準(zhǔn)化處理。
temp['From'] = temp['From'].str.capitalize()
temp['To'] = temp['To'].str.capitalize()
刪除壞數(shù)據(jù)加入整理好的數(shù)據(jù):
將最開(kāi)始的 From_to 列刪除箩绍,加入整理好的 From 和 to 列。
df = df.drop('From_To', axis=1)
df = df.join(temp)
print(df)
去除多余字符:
如同 airline 列中許多數(shù)據(jù)有許多其他字符尺上,會(huì)對(duì)后期的數(shù)據(jù)分析有較大影響材蛛,需要對(duì)這類數(shù)據(jù)進(jìn)行修正。
df['Airline'] = df['Airline'].str.extract(
'([a-zA-Z\s]+)', expand=False).str.strip()
df
格式規(guī)范:
在 RecentDelays 中記錄的方式為列表類型怎抛,由于其長(zhǎng)度不一卑吭,這會(huì)為后期數(shù)據(jù)分析造成很大麻煩。這里將 RecentDelays 的列表拆開(kāi)马绝,取出列表中的相同位置元素作為一列豆赏,若為空值即用 NaN 代替。
delays = df['RecentDelays'].apply(pd.Series)
delays.columns = ['delay_{}'.format(n)
for n in range(1, len(delays.columns)+1)]
df = df.drop('RecentDelays', axis=1).join(delays)
df
數(shù)據(jù)預(yù)處理
信息區(qū)間劃分:
班級(jí)一部分同學(xué)的數(shù)學(xué)成績(jī)表,如下圖所示
df=pd.DataFrame({'name':['Alice','Bob','Candy','Dany','Ella','Frank','Grace','Jenny'],'grades':[58,83,79,65,93,45,61,88]})
但我們更加關(guān)心的是該同學(xué)是否及格掷邦,將該數(shù)學(xué)成績(jī)按照是否>60來(lái)進(jìn)行劃分白胀。
df = pd.DataFrame({'name': ['Alice', 'Bob', 'Candy', 'Dany', 'Ella',
'Frank', 'Grace', 'Jenny'],
'grades': [58, 83, 79, 65, 93, 45, 61, 88]})
def choice(x):
if x > 60:
return 1
else:
return 0
df.grades = pd.Series(map(lambda x: choice(x), df.grades))
df
數(shù)據(jù)去重:
一個(gè)列為A的 DataFrame 數(shù)據(jù),如下圖所示
df = pd.DataFrame({'A': [1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 7]})
嘗試將 A 列中連續(xù)重復(fù)的數(shù)據(jù)清除抚岗。
df = pd.DataFrame({'A': [1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 7]})
df.loc[df['A'].shift() != df['A']]
數(shù)據(jù)歸一化:
有時(shí)候或杠,DataFrame 中不同列之間的數(shù)據(jù)差距太大,需要對(duì)其進(jìn)行歸一化處理宣蔚。
其中向抢,Max-Min 歸一化是簡(jiǎn)單而常見(jiàn)的一種方式,公式如下:
def normalization(df):
numerator = df.sub(df.min())
denominator = (df.max()).sub(df.min())
Y = numerator.div(denominator)
return Y
df = pd.DataFrame(np.random.random(size=(5, 3)))
print(df)
normalization(df)
Pandas 繪圖操作
Series 可視化:
%matplotlib inline
ts = pd.Series(np.random.randn(100), index=pd.date_range('today', periods=100))
ts = ts.cumsum()
ts.plot()
DataFrame 折線圖:
df = pd.DataFrame(np.random.randn(100, 4), index=ts.index,
columns=['A', 'B', 'C', 'D'])
df = df.cumsum()
df.plot()
DataFrame 散點(diǎn)圖:
df = pd.DataFrame({"xs": [1, 5, 2, 8, 1], "ys": [4, 2, 1, 9, 6]})
df = df.cumsum()
df.plot.scatter("xs", "ys", color='red', marker="*")
DataFrame 柱形圖:
df = pd.DataFrame({"revenue": [57, 68, 63, 71, 72, 90, 80, 62, 59, 51, 47, 52],
"advertising": [2.1, 1.9, 2.7, 3.0, 3.6, 3.2, 2.7, 2.4, 1.8, 1.6, 1.3, 1.9],
"month": range(12)
})
ax = df.plot.bar("month", "revenue", color="yellow")
df.plot("month", "advertising", secondary_y=True, ax=ax)