pandas 使用指南(上)
pandas作為一種可以提供類似于R中dataframe數(shù)據(jù)結(jié)構(gòu)的module對(duì)于經(jīng)常進(jìn)行機(jī)器學(xué)習(xí)和數(shù)據(jù)處理的同學(xué)是一種非常高效的數(shù)據(jù)結(jié)構(gòu)工具伞访。Pandas上面已經(jīng)提供了一份簡(jiǎn)易指南铸题,但是全文太長(zhǎng)了(雖然其標(biāo)榜十分鐘內(nèi)可以學(xué)會(huì)),故而決定寫一份旨在給剛剛開始使用pandas的初學(xué)者的簡(jiǎn)化版潦匈,因此如果讀者已經(jīng)有一定的pandas使用經(jīng)驗(yàn)的話粘勒,可以略過本文。
本文的主要內(nèi)容包括:
- 解釋?dataframe的基本結(jié)構(gòu)
- 幾種常見的創(chuàng)建dataframe的方法
- 幾種常用的獲得dataframe中數(shù)據(jù)的方法
- 幾種對(duì)已創(chuàng)建的dataframe進(jìn)行數(shù)據(jù)修改的方法
- dataframe中兩個(gè)常用的函數(shù):groupby以及apply
我們首先導(dǎo)入需要的module:
In [1]: import pandas as pd
In [2]: import numpy as np
基本概念
series
series是pandas中基本的數(shù)據(jù)結(jié)構(gòu)钩蚊,它的結(jié)構(gòu)與一個(gè)list類似,但是卻擁有自己的索引蹈矮。在實(shí)際應(yīng)用中砰逻,dataframe的每一個(gè)列對(duì)一個(gè)series。正因?yàn)檫@些series和dataframe一樣都有索引泛鸟,因此在把一個(gè)series加入到dataframe中時(shí)蝠咆,必須考慮他們的索引是否對(duì)應(yīng)。
In [3]: s1 = pd.Series([1,3,5,6,8])
In [4]: s1
Out[4]:
0 1
1 3
2 5
3 6
4 8
dtype: int64
In [5]: s2 = pd.Series(['a', 'b', 'c'])
In [6]: s2
Out[6]:
0 a
1 b
2 c
dtype: object
dataframe
pandas中的dataframe與R中的dataframe基本類似北滥,可以提供一種類似于表格的數(shù)據(jù)結(jié)構(gòu)刚操,每一列都是一個(gè)series,這些series擁有與整個(gè)dataframe相同的索引再芋。
In [7]: index = range(6)
In [8]: index
Out[8]: [0, 1, 2, 3, 4, 5]
In [9]: df = pd.DataFrame(np.random.randn(6,4), index=index, columns=list('ABCD'))
In [10]: df
Out[10]:
A B C D
0 0.531734 -1.292527 -0.627073 -1.900115
1 -0.715616 2.007529 -0.535181 -0.055376
2 -0.051779 0.751669 -1.150100 1.295839
3 -1.749876 0.962153 0.489654 -0.134320
4 -0.350185 -0.495535 0.116741 1.192340
5 0.844690 -0.111987 -1.221936 -0.714337
索引
索引在dataframe和series中都有應(yīng)用菊霜,簡(jiǎn)單來(lái)看,它是一種類似于整數(shù)array的數(shù)據(jù)結(jié)構(gòu)济赎。
In [11]: df.index
Out[11]: Int64Index([0, 1, 2, 3, 4, 5], dtype='int64')
In [12]: type(df.index)
Out[12]: pandas.indexes.numeric.Int64Index
但是需要注意的是鉴逞,并不是每一個(gè)dataframe和series的索引都一定是從0開始,在數(shù)據(jù)的操作過程中司训,索引有時(shí)候會(huì)發(fā)生變化华蜒。
In [13]: df2 = df[3:5]
In [14]: df2
Out[14]:
A B C D
3 -1.749876 0.962153 0.489654 -0.13432
4 -0.350185 -0.495535 0.116741 1.19234
In [15]: df2.index
Out[15]: Int64Index([3, 4], dtype='int64')
創(chuàng)建dataframe
pandas中的dataframe有很多不同的創(chuàng)建方式,比如可以手動(dòng)一個(gè)一個(gè)創(chuàng)建豁遭,也可以通過讀取文件或者數(shù)據(jù)庫(kù)直接生成叭喜,以下將一一給予簡(jiǎn)單介紹。
手動(dòng)創(chuàng)建
如果沒有已經(jīng)生成的文件或者數(shù)據(jù)庫(kù)的數(shù)據(jù)表蓖谢,我們可能需要手動(dòng)創(chuàng)建一個(gè)dataframe捂蕴,并在程序運(yùn)行過程中不斷賦值等等。手動(dòng)創(chuàng)建的基本命令就是pd.DataFrame(self, data=None, index=None, columns=None, dtype=None, copy=False)
闪幽。
其參數(shù)包括data
啥辨、index
、columns
盯腌、dtype
溉知、copy
,這里我將介紹前三個(gè)變量:
-
data
: 將要存入dataframe的數(shù)據(jù),可以是numpy里面的matrix级乍,也可以是一個(gè)簡(jiǎn)單的2d list舌劳。 -
index
: 一個(gè)可以作為dataframe索引的數(shù)列,注意玫荣,pandas不會(huì)檢查是否有重復(fù)元素甚淡,因此請(qǐng)?jiān)谧鳛樗饕褂们白孕袡z查,以免導(dǎo)致錯(cuò)誤 -
columns
: 一個(gè)string的list捅厂,每一個(gè)元素代表一個(gè)列的名字贯卦,順序與列的順序相同
In [16]: index = [1, 1, 2, 3, 4]
In [17]: index
Out[17]: [1, 1, 2, 3, 4]
In [18]: data = [range(4), range(1, 5), range(2, 6), range(3, 7), range(4, 8)]
In [19]: data
Out[19]: [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7]]
In [20]: df2 = pd.DataFrame(data=data, index=index, columns=list('ABCD'))
In [21]: df2
Out[21]:
A B C D
1 0 1 2 3
1 1 2 3 4
2 2 3 4 5
3 3 4 5 6
4 4 5 6 7
從文件中讀取
以csv文件為例,使用read_csv
函數(shù)即可焙贷。假設(shè)路徑內(nèi)有一個(gè)文件名為weather.csv
撵割,其主要內(nèi)容如下:
,date,rain,snow,weather
0,20160101,0,0,0
1,20160102,0,0,0
2,20160103,0,0,0
3,20160104,0,0,0
4,20160105,0,0,0
5,20160106,0,0,0
6,20160107,0,0,0
7,20160108,0,0,0
8,20160109,1,0,1
9,20160110,1,0,1
10,20160111,0,0,0
其讀取過程如下:
In [22]: df2 = pd.read_csv('weather.csv')
In [23]: df2
Out[23]:
Unnamed: 0 date rain snow weather
0 0 20160101 0 0 0
1 1 20160102 0 0 0
2 2 20160103 0 0 0
3 3 20160104 0 0 0
4 4 20160105 0 0 0
5 5 20160106 0 0 0
6 6 20160107 0 0 0
7 7 20160108 0 0 0
8 8 20160109 1 0 1
9 9 20160110 1 0 1
10 10 20160111 0 0 0
這里,第一列在csv中沒有標(biāo)題辙芍,所以讀取后在dataframe里面的列名稱就叫Unnamed: 0
睁枕。
從sql中讀取
如果要從sql中讀取,我們需要了解一點(diǎn)sql的基本知識(shí)沸手,同時(shí)在python中安裝sqlalchemy
外遇,然后使用read_sql
函數(shù)。
現(xiàn)假設(shè)我們的database中有一個(gè)數(shù)據(jù)表的名字就叫做weather
,其內(nèi)容與csv文件基本一樣,那么示例如下(我們使用postgresql為例瑞驱,但是mysql等等基本相同):
In [24]: from sqlalchemy import create_engine
In [25]: database_engine = create_engine('postgresql://[用戶名]:[對(duì)應(yīng)密碼]@localhost:5432/[database名]', echo=False)
In [26]: weather_df = pd.read_sql("SELECT * FROM weather", con=database_engine)
In [27]: weather_df
Out[27]:
id date rain snow weather
0 0 20160101 0 0 0
1 1 20160102 0 0 0
2 2 20160103 0 0 0
3 3 20160104 0 0 0
4 4 20160105 0 0 0
5 5 20160106 0 0 0
6 6 20160107 0 0 0
7 7 20160108 0 0 0
8 8 20160109 1 0 1
9 9 20160110 1 0 1
10 10 20160111 0 0 0
使用dataframe
dataframe的使用主要在于根據(jù)使用者的需要查看并獲取里面的數(shù)據(jù)。
查看數(shù)據(jù)
dataframe的查看主要包括了解整個(gè)數(shù)據(jù)表的基本信息菲语,了解里面的數(shù)據(jù)大致特征,并查看某特定幾行的數(shù)據(jù)惑灵。下面筆者將一一進(jìn)行介紹山上。
查看數(shù)據(jù)表的基本信息
使用info
函數(shù)。
In [28]: weather_df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 11 entries, 0 to 10
Data columns (total 5 columns):
id 11 non-null int64
date 11 non-null int64
rain 11 non-null int64
snow 11 non-null int64
weather 11 non-null int64
dtypes: int64(5)
memory usage: 512.0 bytes
查看開頭或尾部的數(shù)據(jù)表
查看開頭:使用head
函數(shù)
查看尾部:使用tail
函數(shù)
In [30]: weather_df.head(5)
Out[30]:
id date rain snow weather
0 0 20160101 0 0 0
1 1 20160102 0 0 0
2 2 20160103 0 0 0
3 3 20160104 0 0 0
4 4 20160105 0 0 0
In [31]: weather_df.tail(5)
Out[31]:
id date rain snow weather
6 6 20160107 0 0 0
7 7 20160108 0 0 0
8 8 20160109 1 0 1
9 9 20160110 1 0 1
10 10 20160111 0 0 0
獲取數(shù)據(jù)
此處為了提高程序效率英支,推薦使用一下四個(gè)行數(shù)來(lái)獲取數(shù)據(jù): iloc
佩憾、loc
、iat
干花、at
妄帘。
獲取行或列
獲取多行
In [32]: weather_df[3:8]
Out[32]:
id date rain snow weather
3 3 20160104 0 0 0
4 4 20160105 0 0 0
5 5 20160106 0 0 0
6 6 20160107 0 0 0
7 7 20160108 0 0 0
獲取單行
使用iloc
或者loc
。
In [33]: weather_df.iloc[3]
Out[33]:
id 3
date 20160104
rain 0
snow 0
weather 0
Name: 3, dtype: int64
In [34]: weather_df.loc[3]
Out[34]:
id 3
date 20160104
rain 0
snow 0
weather 0
Name: 3, dtype: int64
此處的iloc
和loc
結(jié)果相同池凄,但并不代表兩者意義一樣抡驼。loc
通過索引獲得對(duì)應(yīng)行,iloc
通過行號(hào)來(lái)獲得對(duì)應(yīng)行肿仑。例如(注意索引)
In [35]: df = weather_df[3:8]
In [36]: df
Out[36]:
id date rain snow weather
3 3 20160104 0 0 0
4 4 20160105 0 0 0
5 5 20160106 0 0 0
6 6 20160107 0 0 0
7 7 20160108 0 0 0
In [37]: df.iloc[3]
Out[37]:
id 6
date 20160107
rain 0
snow 0
weather 0
Name: 6, dtype: int64
In [38]: df.loc[3]
Out[38]:
id 3
date 20160104
rain 0
snow 0
weather 0
Name: 3, dtype: int64
獲取單列
有兩種方式
In [39]: df.date
Out[39]:
3 20160104
4 20160105
5 20160106
6 20160107
7 20160108
Name: date, dtype: int64
In [40]: df['date']
Out[40]:
3 20160104
4 20160105
5 20160106
6 20160107
7 20160108
Name: date, dtype: int64
獲取多列
使用loc
函數(shù)或iloc
函數(shù)
In [41]: df.loc[:, ['date', 'snow']]
Out[41]:
date snow
3 20160104 0
4 20160105 0
5 20160106 0
6 20160107 0
7 20160108 0
In [42]: df.iloc[:, :2]
Out[42]:
id date
3 3 20160104
4 4 20160105
5 5 20160106
6 6 20160107
7 7 20160108
兩者的不同在于致盟,loc
是使用索引和列名稱來(lái)獲得所需的列碎税,iloc
是使用行號(hào)和列號(hào)來(lái)獲取所需的列。
獲取某個(gè)數(shù)據(jù)
要獲取某一個(gè)數(shù)值馏锡,iloc
雷蹂、loc
、iat
眷篇、at
都可以實(shí)現(xiàn)。
In [43]: df.iloc[3, 1]
Out[43]: 20160107
In [44]: df.iat[3, 1]
Out[44]: 20160107
In [45]: df.loc[3, 'date']
Out[45]: 20160104
In [46]: df.at[3, 'date']
Out[46]: 20160104
從該例子可以看出荔泳,iloc
和iat
都是通過行數(shù)和列數(shù)來(lái)獲取特定的單個(gè)元素蕉饼,而loc
和at
都是通過索引和列名稱來(lái)獲取特定的單個(gè)元素。
利用bool下標(biāo)來(lái)獲取數(shù)據(jù)
有些時(shí)候玛歌,我們只希望通過一些判斷或者比較獲得一部分?jǐn)?shù)據(jù)昧港,例如,在weather_df
中支子,我希望獲得以下幾組數(shù)據(jù):
- 獲取日期在20160106到20160110(包括首尾)之間的所有行
- 獲取名稱為weather的列中值為1的所有行
- 獲取日期在[20160106, 20160104, 20160108]這個(gè)list中的所有行
- 以上三組數(shù)據(jù)中创肥,每組我只想獲得id, date和weather這三列
示例將按順序完成以上幾項(xiàng):
In [47]: weather_df[(weather_df['date'] >= 20160106) & (weather_df['date'] <= 20160110)]
Out[47]:
id date rain snow weather
5 5 20160106 0 0 0
6 6 20160107 0 0 0
7 7 20160108 0 0 0
8 8 20160109 1 0 1
9 9 20160110 1 0 1
In [48]: weather_df[weather_df['weather'] == 1]
Out[48]:
id date rain snow weather
8 8 20160109 1 0 1
9 9 20160110 1 0 1
In [49]: weather_df[weather_df.date.isin([20160106, 20160104, 20160108])]
Out[49]:
id date rain snow weather
3 3 20160104 0 0 0
5 5 20160106 0 0 0
7 7 20160108 0 0 0
In [50]: weather_df[(weather_df['date'] >= 20160106) & (weather_df['date'] <= 20160110)].loc[:, ['id', 'date', 'weather']]
Out[50]:
id date weather
5 5 20160106 0
6 6 20160107 0
7 7 20160108 0
8 8 20160109 1
9 9 20160110 1
In [51]: weather_df[weather_df['weather'] == 1].loc[:, ['id', 'date', 'weather']]
Out[51]:
id date weather
8 8 20160109 1
9 9 20160110 1
In [52]: weather_df[weather_df.date.isin([20160106, 20160104, 20160108])].loc[:, ['id', 'date', 'weather']]
Out[52]:
id date weather
3 3 20160104 0
5 5 20160106 0
7 7 20160108 0
通過上述幾個(gè)例子,我們可以發(fā)現(xiàn)通過條件判斷來(lái)獲取部分?jǐn)?shù)據(jù)的基本格式就是類似于dataframe[dataframe.column > value]
或者dataframe[dataframe.column.isin(list)]
值朋。
那么其原理呢叹侄?
事實(shí)上他們先根據(jù)方括號(hào)內(nèi)的條件判斷生成了一個(gè)由bool值構(gòu)成的series: (weather_df['date'] >= 20160106) & (weather_df['date'] <= 20160110)
, weather_df['weather'] == 1
或者weather_df.date.isin([20160106, 20160104, 20160108])
。
然后在根據(jù)這個(gè)新的series來(lái)選取bool值為true的行昨登。
In [53]: weather_df
Out[53]:
id date rain snow weather
0 0 20160101 0 0 0
1 1 20160102 0 0 0
2 2 20160103 0 0 0
3 3 20160104 0 0 0
4 4 20160105 0 0 0
5 5 20160106 0 0 0
6 6 20160107 0 0 0
7 7 20160108 0 0 0
8 8 20160109 1 0 1
9 9 20160110 1 0 1
10 10 20160111 0 0 0
In [54]: weather_df.date.isin([20160106, 20160104, 20160108])
Out[54]:
0 False
1 False
2 False
3 True
4 False
5 True
6 False
7 True
8 False
9 False
10 False
Name: date, dtype: bool
In [55]: weather_df[weather_df.date.isin([20160106, 20160104, 20160108])]
Out[55]:
id date rain snow weather
3 3 20160104 0 0 0
5 5 20160106 0 0 0
7 7 20160108 0 0 0
常用到的判斷主要包括數(shù)值的大小以及元素是否在給定的list或者set中趾代,前者用>
, >=
, <
, 或者<=
,后者用.isin
丰辣。多個(gè)邏輯判斷的連接使用&
或者|
撒强。
當(dāng)然也存在更加復(fù)雜的邏輯判斷,比如判定某一個(gè)dataframe中某一個(gè)string構(gòu)成的列的每一個(gè)元素的第三到第六個(gè)構(gòu)成的substring必須在某個(gè)給定區(qū)間笙什,我的常用方法是使用apply函數(shù)飘哨,這部分內(nèi)容將在后面給出解釋和示例。
剩下的在后半部繼續(xù)寫吧琐凭。