Pandas 是Python的核心數據分析支持庫,提供了快速、靈活、明確的數據結構,旨在簡單、直觀地處理關係型、標記型數據。Pandas常用於處理帶行列標籤的矩陣數據、與 SQL 或 Excel 表類似的表格數據,應用於金融、統計、社會科學、工程等領域裏的數據整理與清洗、數據分析與建模、數據可視化與製表等工作。
數據類型:Pandas 不改變原始的輸入數據,而是複製數據生成新的對象,有普通對象構成的一維數組成爲Series
,由Series構成的二維數組表稱爲DataFrame
,其行被稱爲index
,列爲Column
。
安裝:如果使用anaconda集成環境則會自動安裝numpy、scipy、pandas等數據科學包,也可以通過python包管理工具安裝pandas:pip install pandas
1、數據對象的創建
通過Series()
包裹一維數組可以創建Series對象,其中數組的元素可以是各種類型。
通過DataFrame()
包裹二維數組可以創建一個DataFrame對象,可以通過參數index
、columns
指定行標籤和列標籤。也可以通過python的字典類型初始化DataFrame,其鍵名默認爲列標籤
import pandas as pd
import numpy as np
# 通過一維數組初始化Series
s = pd.Series([1, 2.0, np.nan, 'test'])
print(s)
'''
0 1
1 2
2 NaN
3 test
dtype: object
'''
# 通過二維數組初始化DataFrame
arr = np.random.randn(6, 4)
arr_df = pd.DataFrame(arr, index=np.arange(1, 7), columns=list('ABCD'))
print(arr_df)
'''
A B C D
1 -0.085417 -0.816502 1.495134 -0.277742
2 1.657144 -0.203346 0.631930 -1.182239
3 -2.303923 -0.535696 1.315379 0.129682
4 0.133198 -0.239664 -2.004494 0.119965
5 -1.454717 2.114255 -0.538678 -0.580361
6 -0.759183 0.141554 -0.243270 2.840325
'''
# 通過字典dict初始化DataFrame
dic = {'A': 1.,
'B': pd.Timestamp('20130102'),
'C': pd.Series(1, index=list(range(4)), dtype='float32'),
'D': np.array([3] * 4, dtype='int32'),
'E': pd.Categorical(["test", "train", "test", "train"])
}
dic_df = pd.DataFrame(dic)
print(dic_df)
'''
A B C D E
0 1.0 2013-01-02 1.0 3 test
1 1.0 2013-01-02 1.0 3 train
2 1.0 2013-01-02 1.0 3 test
3 1.0 2013-01-02 1.0 3 train
'''
注意到在使用“=”傳遞或選擇DataFrame時,產生的使原數據的引用,修改引用原數據也會發生改變。
可以使用copy()
創建一個新的數據,這樣對副本的任何操作不會影響原數據。如果數據中含有對象,那麼copy()會創建新的內存保存對象,但對象的具體值仍然是引用原對象,這就是淺拷貝。若希望拷貝對象的同時拷貝值,可以採用深拷貝,這時需指定屬性deep=True
。有的時候我們直接在原DataFrame上操作數據會報錯 如下,這時候我們需要在原Dataframe後加上.copy()
生成副本再進行操作。
SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame
df = pd.DataFrame({'A': [1, 2],
'B': [3, 4]})
row_cp = df.iloc[1].copy()
row_cp['A'] = 6 # 對副本修改,原來的df不會改變
print(df)
row = df.iloc[1]
row['A'] = 5 # 修改引用,原來的df隨之發生改變
print(df)
'''
A B
0 1 3
1 2 4
A B
0 1 3
1 5 4
'''
2、查看數據
函數head(n)
可以查看DataFrame前n行的數據,tail(n)
查看倒數n行的數據
index()
查看DataFrame的行標籤,columns顯示列標籤
describe()
按列顯示數據的統計信息,包括計數、均值、方差、最小最大值等。
函數mean()
顯示所有列的均值,mean(1)顯示所有行的均值
sum()
求所有列的和,sum(1)求所有行的和
DataFrame有一個empty
屬性用於判斷是否爲空,若爲空則返回True
arr = np.random.randn(6, 4)
df = pd.DataFrame(arr, index=np.arange(1, 7), columns=list('ABCD'))
print(df.head(3))
print(df.index)
print(df.describe())
'''
# 查看前三行數據
A B C D
1 3.260449 -0.619396 0.070877 1.586914
2 -0.529708 0.071917 -1.919316 1.845727
3 -1.005765 2.176579 -0.323483 -1.295067
# 查看行標籤
Int64Index([1, 2, 3, 4, 5, 6], dtype='int64')
# 查看統計信息
A B C D
count 6.000000 6.000000 6.000000 6.000000
mean -0.184606 -0.487184 0.079433 0.855810
std 1.721394 1.800460 1.379498 1.128764
min -1.443635 -3.091446 -1.919316 -1.295067
25% -0.967105 -1.430192 -0.281188 0.778729
50% -0.694488 -0.273739 -0.041713 1.150944
75% -0.531744 0.197755 0.355731 1.508475
max 3.260449 2.176579 2.352142 1.845727
'''
3、數據的選擇
可以像python的list一樣直接對DataFrame對象進行切片,選取列或者行,
# 選取一個列A,等價於df['A']
print(df.A)
# 選取第1到第3行,行下標從0開始
print(df[1:3])
'''
# 標籤爲A的那一列
1 0.644427
2 0.643149
3 1.374668
4 -0.154465
5 -0.338085
6 -1.989284
Name: A, dtype: float64
# 第1~3行
A B C D
2 0.643149 1.769001 -0.166028 -0.036854
3 1.374668 -0.118593 -0.202222 0.308353
'''
通過loc[]
方法可以通過具體的標籤值對DataFrame的一行、一列、幾行幾列進行選擇
# 取出行標籤爲2的那一行
print(df.loc[2])
# 取出行標籤爲1~3,列標籤爲'A','B'的內容
print(df.loc[1:3, ['A', 'B']])
# 獲取行標籤爲1,列標籤爲'A'的具體值,等價於df.at[1,'A']
print(df.loc[1, 'A'])
'''
# 標籤爲2的一行
A 0.681469
B -0.053046
C -1.384877
D -0.447700
Name: 2, dtype: float64
# 標籤爲1~3,列標籤爲'A','B'的內容
A B
1 0.710907 -0.950896
2 0.681469 -0.053046
3 0.781981 0.123072
# 行標籤爲1,列標籤爲'A'的具體值
0.7109074858947351
'''
除了通過行列標籤來進行取值以外,還可以通過行列的數組的位置進行取值,其方法名爲iloc[]
# 取出第一行,行下標從0開始
print(df.iloc[0])
# 顯示第1,2,4行的第0,2列
print(df.iloc[[1, 2, 4], [0, 2]])
# 顯示第1行第1列的具體值,等價於df.iat[1,1]
print(df.iloc[1, 1])
還可以根據True/False確定是否選擇數據,例如選擇所有指定字段>0、等於指定值的數據行
# 輸出A那一列大於0的所有行
print(df[df.A > 0])
df['E'] = ['one', 'one', 'two', 'three', 'four', 'three']
# 選擇E的值爲two的行
print(df[df['E'] == 'two'])
# 輸出E那一列存在two、four的所有行
print(df[df['E'].isin(['two', 'four'])])
'''
A B C D
3 0.168998 -0.732362 -0.098542 0.413128
5 0.513677 -0.163231 -0.098037 -0.606693
A B C D E
3 0.168998 -0.732362 -0.098542 0.413128 two
A B C D E
3 0.168998 -0.732362 -0.098542 0.413128 two
5 0.513677 -0.163231 -0.098037 -0.606693 four
'''
4、操作數據
通過insert()
方法可以實現在指定位置插入一列,也可以直接將一個數組賦值給DataFrame,這將默認添加到最後一列
可以通過之前的選擇方法loc、iloc找到指定的行列,然後直接賦值,如果該位置存在數據則會修改,否則添加
通過iterrows()
方法可以對DataFrame進行行遍歷,在每一行通過關鍵字或列名操作每一個具體數據
通過drop()
方法刪除指定的數據,index屬性指定刪除的行,columns指定刪除的列,drop_duplicates()
指定刪除重複的數據。
pandas對數據的操作不回在原數據表上生效,需要一個左值來接收操作的結果。如果希望在原數據上進行操作,需要指定屬性inplace=True
df = pd.DataFrame(data = [['lisa','f',22],['joy','f',22],['tom','m',21]],
index = [1,2,3],columns = ['name','sex','age'])
citys = ['ny','zz','xy']
#在第0列,加上column名稱爲city,值爲citys的數值。
df.insert(0,'city',citys)
jobs = ['student','AI','teacher']
# 默認在df最後一列加上column名稱爲job,值爲jobs的數據。
df['job'] = jobs
# 若df中沒有index爲“4”的這一行的話,則添加,否則修改
df.loc[4] = ['zz', 'mason', 'm', 24, 'engineer']
print(df)
'''
city name sex age job
1 ny lisa f 22 student
2 zz joy f 22 AI
3 xy tom m 21 teacher
4 zz mason m 24 engineer
'''
# 修改某一列
df['age'] += 1
print(df)
'''
name sex age
1 lisa f 23
2 joy f 23
3 tom m 22
'''
# 遍歷每一行
for index,rows in df.iterrows():
print(index,rows)
'''
1 name lisa
sex f
age 22
Name: 1, dtype: object
2 name joy
sex f
age 22
Name: 2, dtype: object
3 name tom
sex m
age 21
Name: 3, dtype: object
'''
# 刪除行標籤爲1的行
dp=df.drop(index=1)
print(dp)
'''
city name sex age job
2 zz joy f 22 AI
3 xy tom m 21 teacher
4 zz mason m 24 engineer
'''
# 在原數據集上刪除列標籤爲sex的列
df.drop(columns=['sex'],inplace=True)
print(df)
'''
city name age job
1 ny lisa 22 student
2 zz joy 22 AI
3 xy tom 21 teacher
4 zz mason 24 engineer
'''
# 在原數據集上刪除age列重複的數據,只保留第一個
df.drop_duplicates(subset='age', keep='first', inplace=True)
print(df)
'''
name sex age
1 lisa f 22
3 tom m 21
'''
對DataFrame進行轉置操作,調用.T
sort_index(axis=1, ascending=False)
對數據進行排序,axis=0
代表按行標籤排序,axis=1
代表按列標籤排序
sort_values(by='A')
按某一列的值對數據進行排序,這裏是按列標籤爲A的
apply()
函數對DataFrame的每一行應用函數
set_index("col")
可以設置DataFrame的索引列爲指定的col。
reset_index()
將原來的索引添加爲列,並新增一個從0開始的數字作爲索引。
特別注意的是上面的操作需要左值來接收修改後的結果,不會直接修改原來的DataFrame。
# 數據轉置
print(df.T)
'''
1 2 3 4 5 6
A -1.176180 -1.301768 0.907088 -1.528101 1.098978 -1.280193
B -0.461954 -0.749642 1.169118 -0.297765 0.531088 -0.999842
C -1.715094 -0.512856 0.511861 -0.247240 1.696772 -0.902995
D 1.336999 0.209091 2.254337 0.649625 -0.049886 -1.514815
'''
# 按列標籤倒序
si=df.sort_index(axis=1, ascending=False)
print(si)
'''
D C B A
1 1.336999 -1.715094 -0.461954 -1.176180
2 0.209091 -0.512856 -0.749642 -1.301768
3 2.254337 0.511861 1.169118 0.907088
4 0.649625 -0.247240 -0.297765 -1.528101
5 -0.049886 1.696772 0.531088 1.098978
6 -1.514815 -0.902995 -0.999842 -1.280193
'''
# 按列A的值遞增對行排序
sv=df.sort_values(by='A')
print(sv)
'''
A B C D
4 -1.528101 -0.297765 -0.247240 0.649625
2 -1.301768 -0.749642 -0.512856 0.209091
6 -1.280193 -0.999842 -0.902995 -1.514815
1 -1.176180 -0.461954 -1.715094 1.336999
3 0.907088 1.169118 0.511861 2.254337
5 1.098978 0.531088 1.696772 -0.049886
'''
# 應用匿名函數,用每一列最大值減去最小值
df.apply(lambda x: x.max() - x.min())
print(df)
'''
A 2.073961
B 2.671590
C 1.785291
D 0.000000
F 4.000000
dtype: float64
'''
panda的concat
函數可以將兩個相同類型的DataFrame在行的維度上進行拼接
merge()
函數可以將不同DataFrame按列拼接
append()
函數可以在DataFrame的結尾追加,其索引值不會改變,如果希望追加之後重排索引值,需指定屬性ignore_index=True
,注意需要用左值來接收append後的結果
# 將第一行和最後一行拼接
print(pd.concat([df[:1], df[-2:-1]]))
'''
# 按行拼接
A B C D
1 -0.527221 -0.754650 -2.385270 -2.569586
5 0.054059 1.443911 -0.240856 -1.501045
'''
# 將第4行追加到結尾,索引值不變
df = df.append(df.iloc[3])
print(df)
'''
A B C D
1 -0.527221 -0.754650 -2.385270 -2.569586
2 2.123332 -0.013431 -0.574359 -0.548838
3 -0.244057 -0.267805 1.089026 -0.022174
4 -0.789228 1.171906 0.526318 0.046655
5 0.054059 1.443911 -0.240856 -1.501045
6 0.756844 0.623305 -0.597299 0.034326
4 -0.789228 1.171906 0.526318 0.046655
'''
# 將兩個DataFrame按列拼接
df1 = pd.DataFrame({'row1': ['foo', 'bar'], 'row2': [1, 2]})
df2 = pd.DataFrame({'row1': ['foo', 'bar'], 'row3': [4, 5]})
print(pd.merge(df1, df2))
'''
row1 row2 row3
0 foo 1 4
1 bar 2 5
'''
groupby()
可以數據按列進行分組,分組後的結果可以使用for循環進行迭代,迭代中每個分組是一個(index,DataFrame)
元組,可以對其中的DataFrame作進一步操作。之後可以直接將sum()
、mean()
等聚合函數用於分組結果上,也可用agg()
對指定列使用指定的聚合函數。
stack()
可以將多列的數據壓縮爲兩列顯示
df = pd.DataFrame({'A': ['foo', 'bar', 'foo', 'bar'],
'B': ['one', 'two', 'one', 'three'],
'C': np.random.randn(4),
'D': np.random.randn(4)})
# 按A、B兩列進行分組
dg=df.groupby(['A', 'B'])
for (index,df) in dg:
print(df)
'''
A B C D
3 bar three 0.895239 0.17702
A B C D
1 bar two -0.391467 2.485707
A B C D
0 foo one -1.516292 0.108226
2 foo one 1.909878 -1.469921
C D
'''
# 對分組求和
print(dg.sum())
'''
A B
bar three 0.895239 0.177020
two -0.391467 2.485707
foo one 0.393586 -1.361695
'''
# 按A列進行分組並求C的最大最小值
dg = df.groupby(['A']).agg({'C': ['max', 'min']})
print(dg)
'''
C
max min
A
bar 1.466636 0.178420
foo 0.782000 -1.246935
'''
# 壓縮
print(df.stack())
'''
0 A foo
B one
C -1.51629
D 0.108226
2 A foo
B one
C 1.90988
D -1.46992
'''
shift()
可以將一列數據平移指定位置,diff()
用原數據減去平移後的數據
df = pd.DataFrame([1, 2, 3, 4, 5])
print(df.shift(2)) # 向後平移兩個位置
print(df.diff(2)) # 原數據減去平移兩位後的差
'''
0
0 NaN
1 NaN
2 1.0
3 2.0
4 3.0
0
0 NaN
1 NaN
2 2.0
3 2.0
4 2.0
'''
Pandas主要使用值np.nan
來表示缺失的數據。可以使用dropna(how='any')
方法來刪除所有存在空值的行,dropna(axis=1)
刪除存在空值的列。fillna(value=x)
用指定值x填充所有的空值。
5、時間索引
pandas中通過Timestamp
對象來處理時間類型,可以通過Timestamp()
方法創建一個時間對象,或通過to_datetime()
可以將字符串轉化爲Timestamp對象,從而根據時間來排序。由於Timestamp是從Python標準庫的datetime類繼承過來的,所以其用法相似。
data = pd.DataFrame()
time_str = ['2020-03-24T22:24:01.000Z', '2020-03-24T22:26:11.000Z', '2020-03-24T22:25:11.000Z']
data['timestamp'] = pd.to_datetime(time_str, format='%Y-%m-%dT%H:%M:%S.%fZ') # 格式化時間字符串
data.sort_values(by=['timestamp'], inplace=True, ascending=True)
print(data)
'''
timestamp
0 2020-03-24 22:24:01
2 2020-03-24 22:25:11
1 2020-03-24 22:26:11
'''
兩個Timestamp對象作差得到的是時間差對象Timedelta
,也可以通過Timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)
來創建。同樣地它也是繼承自python標準庫datetime。
它具有兩個屬性days
和seconds
,對應時間間隔是幾天零幾秒。Timedelta和Timestamp相加可以得到另一個Timestamp對象。
time_list = ['2020-06-01 12:00', '2020-06-02 13:00', '2020-06-05 15:00']
time_list = pd.to_datetime(time_list, format="%Y-%m-%d %H:%M")
time_delta = time_list[1] - time_list[0] # 作差得到Timedelta
print('時間間隔:', time_delta, '其中包括', time_delta.days, '天+', time_delta.seconds, '秒')
'''
時間間隔: 1 days 01:00:00 其中包括 1 天+ 3600 秒
'''
time_delta = pd.Timedelta(days=1, hours=2, minutes=30) # 創建Timedelta對象
print(time_list[2] + time_delta) # 相加得Timestamp
'''
2020-06-06 17:30:00
'''
pandas提供了DatetimeIndex
對象用於將時間序列當作索引來操作數據。首先使用DatetimeIndex()
可以將一維數組序列轉化爲DatetimeIndex對象。通過操作時間索引可以像數字索引那樣進行數據的選擇、切片操作。
# 創建時間戳序列
date_index = pd.DatetimeIndex(['4/1/2019','4/2/2019','4/2/2019','4/2/2019','4/3/2019'])
# 將序列設爲索引
ts = pd.Series(np.arange(5),index=date_index)
print(ts)
'''
2019-04-01 0
2019-04-02 1
2019-04-02 2
2019-04-02 3
2019-04-03 4
dtype: int32
'''
# 按照時間索引對數據進行選擇
print(ts['2019-4-2'])
'''
2019-04-02 1
2019-04-02 2
2019-04-02 3
dtype: int32
'''
# 按時間切片
print(ts['2019-4-1':'2019-4-2'])
'''
2019-04-01 0
2019-04-02 1
2019-04-02 2
2019-04-02 3
dtype: int32
'''
除此之外還可以通過period_range()
/date_range()
來創建時間序列,該方法可以接收起始時間、中止時間、時間頻率、時間長度作爲參數,這四個參數至少要有三個才能確定一個時間序列
# 在指定時間間隔以天爲頻率生成時間序列
print(pd.date_range('2019-01-01','2019-01-10',freq='D'))
'''
DatetimeIndex(['2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04',
'2019-01-05', '2019-01-06', '2019-01-07', '2019-01-08',
'2019-01-09', '2019-01-10'],
dtype='datetime64[ns]', freq='D')
'''
# 從5.1日12點開始以10秒爲頻率生成長度爲5的序列
print(pd.date_range('2019-5-1 12:00:00',freq='10S',periods=5))
'''
DatetimeIndex(['2019-05-01 12:00:00', '2019-05-01 12:00:10',
'2019-05-01 12:00:20', '2019-05-01 12:00:30',
'2019-05-01 12:00:40'],
dtype='datetime64[ns]', freq='10S')
'''
對於pandas中時間類型的Series序列,通常可以用.dt屬性來獲取詳細的時間信息
time_list = ['2020-06-01 12:00:00', '2020-06-02 13:00:00', '2020-06-05 15:00:00']
df = pd.DataFrame({'timestamp': time_list, 'num': [1, 2, 3]})
df['timestamp'] = pd.to_datetime(df['timestamp'])
print(df['timestamp'].dt.hour) # 獲取timestamp類Series的時間屬性
time_delta = df['timestamp'].diff(1) # 相鄰時間作差
print(time_delta.dt.days) # 獲取timedelta類Series的時間屬性
'''
0 12
1 13
2 15
Name: timestamp, dtype: int64
0 NaN
1 1.0
2 3.0
Name: timestamp, dtype: float64
'''
6、其他
通過pandas可以便捷地從其他格式文件進行轉換。
# 將DataFrame寫入csv文件
df.to_csv('foo.csv')
# 從csv文件讀數據
df = pd.read_csv('foo.csv')
# excel文件的讀寫
df = pd.read_excel('foo.xlsx', 'Sheet1', index_col=None, na_values=['NA'])
df.to_excel('foo.xlsx', sheet_name='Sheet1')
在讀取文件時如果原文件中有列標籤,可以使用header
來指定列名,否則可以令header=None,然後使用names
屬性來自己指定列標籤名。使用index_col
屬性來指定第幾列作爲行索引值,這樣就可以通過索引值對行進行查找。pandas默認low_memory=True
在內部對文件進行分塊處理,從而在解析時減少了內存使用。如果數據類型不統一,則需要將low_memory設爲False,或者通過屬性dtype
指定讀取文件列的數據類型。
例如有如下表格數據node.csv,使用header=0指定第一行作爲列名,也可以自己設置列名並指定數據類型
TRANS_NODE_NAME | LONGITUDE | LATITUDE | COUNTRY |
---|---|---|---|
NP1_POK | 83.975602 | 28.20403 | Nepal |
NP1_NEP | 81.361656 | 28.023097 | India |
LK1_SK2 | 79.872208 | 7.075681 | Sri Lanka |
# 使用第一行作爲列名
nodes=pd.read_csv('node.csv',header=0)
# 自定義列名並指定行索引
nodes = pd.read_csv('node.csv', header=None, names=['node', 'longtude', 'latitude', 'country'], index_clo='node',
dtype={'node': str, 'longitude': np.float16, 'latitude': np.float16, 'country': str})
# 使用指定的行索引查找數據
print(nodes['NP1_POK'])
pandas結合matplot可以便捷地進行數據繪圖
ts = pd.Series(np.random.randint(0, 500, len(rng)), index=rng)
# 將數據追加到一個數組統一顯示
ts=ts.cumsum()
# 調用matplot繪製圖
ts.plot()