寫在前面的話
在做天文數據處理的過程中,基本上是和類表格數據打交道,因此在處理天文數據的過程中pandas就是自己首選。利用pandas可以很方便的提取出自己想要的行或列的數據,方便自己后面做統(tǒng)計分析。因此,寫一篇pandas入門的文章記錄一下自己學習pandas的總結。
推薦另外一篇pandas入門文檔:10 Minutes to pandas
pandas的功能
- 具備按軸自動或顯式數據對齊功能的數據結構。這可以防止許多由于數據未對齊以及來自不同數據源(索引方式不同)的數據而導致的常見錯誤。
- 集成時間序列功能。
- 既能處理時間序列數據也能處理非時間序列數據的數據結構。
- 數學運算和約簡(比如對某個軸求和)可以根據不同的元數據(軸號)執(zhí)行。
- 靈活處理缺失數據。
- 合并及其他出現在常見數據庫(例如基于SQL的)中的關系型運算。
pandas引入約定
import pandas as pd
from pandas import Series,DataFrame
pandas數據結構介紹
要使用pandas,必須先要熟悉它的兩個主要數據結構:Series和Data Frame。
Series
Series是一種類似于一維數組的對象,它由一組數據和一組與之相關的數據標簽(索引)組成。
由一組數據生產簡單的Series
a = [1,3,'hello',4.5]
b =pd.Series(a)
print(b)
0 1
1 3
2 hello
3 4.5
dtype: object
Series的表現形式為:索引在左邊,值在右邊。由于沒有為數據指定索引,默認自動創(chuàng)建一個0到n-1(n為數據的長度)的整數型索引。可以通過Series的values和index屬性獲取其數組表示形式和索引對象:
b.values
array([1, 3, 'hello', 4.6], dtype=object)
b.index #like range(4)
RangeIndex(start=0, stop=4, step=1)
通過索引可以獲取對應的值:
b[2]
'hello'
b[1:3]
1 3
2 hello
dtype: object
b[[1,2]]
1 3
2 hello
dtype: object
自定義索引:
a = [1,3,'hello',4.5]
c = pd.Series(a,index=[c,d,m,n])
print(c)
c 1
d 3
m hello
n 4.6
dtype: object
c['d']
3
c[['m','n']]
m hello
n 4.6
dtype: object
使用Numpy函數或者Numpy的運算,都會保留索引值的鏈接:
obj =pd.Series([1,5,7,3,2,-3])
print(obj)
0 1
1 5
2 7
3 3
4 2
5 -3
dtype: int64
obj[obj<3]
0 1
4 2
5 -3
dtype: int64
obj + 1
0 2
1 6
2 8
3 4
4 3
5 -2
dtype: int64
可以將Series看成是一個定長的有序字典,因為它是索引值到數據值的一個映射。
print(c)
c 1
d 3
m hello
n 4.6
dtype: object
'm' in c
True
's' in c
False
如果數據被存放在一個Python字典中,可以直接通過這個字典來創(chuàng)建Series。
data = {'Tom':25,'Jerry':23,'Allon':26,'xiaoming':7}
sdata = Series(data)
sdata
Tom 25
Jerry 23
Allon 26
xiaoming 7
dtype: int64
如果只傳入一個字典,則結果Series中的索引就是原字典中的鍵(Key)。當然你也可以傳入排好序的字典的鍵來改變順序。
name = ['Jerry','xiaoming','Tom','Bob']
obj1 = Series(data,index=name)
print(obj1)
Jerry 23.0
xiaoming 7.0
Tom 25.0
Bob NaN
dtype: float64
由于'Bob'所對應的值找不到,所以就顯示NAN(not a number),在pandas中NAN用于表示缺失或者NA值。由于'Allon'不在name中,所以它被從結果中除去。
pandas中的isnull和notnull函數可用于檢查缺失的數據:
pd.isnull(obj1)
Jerry False
xiaoming False
Tom False
Bob True
dtype: bool
#Series也有類似的用法,是指已經導入Series函數
obj1.isnull()
Jerry False
xiaoming False
Tom False
Bob True
dtype: bool
Series會根據運算的索引自動對齊數據(類似join操作):
obj2 = Series({'a':4,'d':6,'k':8,'f':7})
obj3 = Series({'d':1,'f':3,'a':6,'n':5})
obj2 + obj3
a 10.0
d 7.0
f 10.0
k NaN
n NaN
dtype: float64
Series的name屬性,該屬性與pandas其它關鍵功能關系密切:
obj1
Jerry 23.0
xiaoming 7.0
Tom 25.0
Bob NaN
dtype: float64
obj1.name = 'population'
obj1.index.name = 'name'
print(obj1)
name
Jerry 23.0
xiaoming 7.0
Tom 25.0
Bob NaN
Name: population, dtype: float64
Series的索引值可以通過賦值方式就地修改:
obj2
a 4
d 6
k 8
f 7
dtype: int64
obj2.index = ['e','f','h','m']
obj2
e 4
f 6
h 8
m 7
dtype: int64
DataFrame
DataFrame是一個表格型的數據結構,它含有一組有序的列,每列可以是不同的值類型(數值、字符串、布爾值等)。DataFrame既有行索引也有列索引。
建DataFrame的辦法有很多,最常用的一種是直接傳入一個由等長列表或Numpy數組組成的字典:
data1 = {'state' : ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'],
'year' : [2000, 2001, 2002, 2001, 2002, 2003],
'pop' : [1.5, 1.7, 3.6, 2.4, 2.9, 3.2] }
frame = pd.DataFrame(data1)
frame
state year pop
0 Ohio 2000 1.5
1 Ohio 2001 1.7
2 Ohio 2002 3.6
3 Nevada 2001 2.4
4 Nevada 2002 2.9
5 Nevada 2003 3.2
我自己常用的構建DataFrame的方法:
f = [8,5,3,7]
m = [15,75,34,52]
fm = pd.DataFrame([f,m])
fm
0 1 2 3
0 8 5 3 7
1 15 75 34 52
沒有索引(行or列),DataFrame會自動加上(跟Series一樣)。
對于特別大的DataFrame,head函數會選取前五行:
frame.head()
state year pop
0 Ohio 2000 1.5
1 Ohio 2001 1.7
2 Ohio 2002 3.6
3 Nevada 2001 2.4
4 Nevada 2002 2.9
如果指定列序列,則DataFrame的列就會按照指定的順序排列:
pd.DataFrame(data1, columns=['year','pop','state'])
year pop state
0 2000 1.5 Ohio
1 2001 1.7 Ohio
2 2002 3.6 Ohio
3 2001 2.4 Nevada
4 2002 2.9 Nevada
5 2003 3.2 Nevada
通過類似字典標記的方式或屬性的方式,可以將DataFrame的某一列獲取為一個Series:
frame['pop']
0 1.5
1 1.7
2 3.6
3 2.4
4 2.9
5 3.2
Name: pop, dtype: float64
frame.year
0 2000
1 2001
2 2002
3 2001
4 2002
5 2003
Name: year, dtype: int64
提示:返回的Series擁有原DataFrame相同的索引,而且name屬性也被相應的設置好了。
行也可以通過位置或者名稱進行獲取,比如用loc屬性
frame
state year pop
0 Ohio 2000 1.5
1 Ohio 2001 1.7
2 Ohio 2002 3.6
3 Nevada 2001 2.4
4 Nevada 2002 2.9
5 Nevada 2003 3.2
frame.loc[0]
state Ohio
year 2000
pop 1.5
Name: 0, dtype: object
列可以通過賦值的方式進行修改:
frame['pop'] = 2.0
frame
state year pop
0 Ohio 2000 2.0
1 Ohio 2001 2.0
2 Ohio 2002 2.0
3 Nevada 2001 2.0
4 Nevada 2002 2.0
5 Nevada 2003 2.0
將列表或數組賦值給某個列時,其長度必須跟DataFrame的長度相匹配。如果賦值的是一個Series,就會精確匹配DataFrame的索引,所有的空位都將被填上缺失值。
#此例是直接添加某一列,當pop列本身存在時,就是賦值。
frame['pop'] = np.arange(6.)
frame
state year pop
0 Ohio 2000 0.0
1 Ohio 2001 1.0
2 Ohio 2002 2.0
3 Nevada 2001 3.0
4 Nevada 2002 4.0
5 Nevada 2003 5.0
#Series
val = pd.Series([1.2,4.3,5.7], index=[0,3,5])
frame['add'] = val
frame
state year pop add
0 Ohio 2000 0.0 1.2
1 Ohio 2001 1.0 NaN
2 Ohio 2002 2.0 NaN
3 Nevada 2001 3.0 4.3
4 Nevada 2002 4.0 NaN
5 Nevada 2003 5.0 5.7
使用del函數可以刪除某一列:
del frame['pop']
frame
state year
0 Ohio 2000
1 Ohio 2001
2 Ohio 2002
3 Nevada 2001
4 Nevada 2002
5 Nevada 2003
另一種常見的數據形式是嵌套字典:
data2 = {'Nevada':{2001:2.4, 2002:2.9},
'Ohio':{2000:1.5, 2001:1.7, 2002:3.6}}
frame1 = pd.DataFrame(data2)
frame1
Nevada Ohio
2000 NaN 1.5
2001 2.4 1.7
2002 2.9 3.6
Tips:外層字典的鍵作為列,內層字典的鍵作為行索引。
對DataFrame進行轉值:
frame1.T
2000 2001 2002
Nevada NaN 2.4 2.9
Ohio 1.5 1.7 3.6
設置DataFrame的index和columns的name屬性:
frame1.index.name = 'year'
frame1.columns.name = 'state'
frame1
state Nevada Ohio
year
2000 NaN 1.5
2001 2.4 1.7
2002 2.9 3.6
可以輸入給DataFrame構造器的數據類型:

pandas基本功能
本節(jié)介紹處理Series和DataFrame中的數據的基本手段,更詳細的pandas庫介紹可以看官網文檔User_Guide。
重新索引
pandas中的reindex是創(chuàng)建一個新的對象,使得數據符合新的索引。如果某個索引值當前不存在,則填入確實值。
obj4 = pd.Series([4.5,7.2,-5.3,3.6], index=['d','b','a','c'])
obj4
d 4.5
b 7.2
a -5.3
c 3.6
dtype: float64
obj5 = obj4.reindex(['a','b','c','d','e'])
obj5
a -5.3
b 7.2
c 3.6
d 4.5
e NaN
dtype: float64
reindex函數的參數
| 參數 | 說明 |
|---|---|
| index | 用作索引的新序列 |
| method | 插值(填充)方式,ffill or pad 向前填充值;bfill or backfill 向后填充值 |
| fill_value | 引入缺失值時使用的替代值 |
| limit | 向前或向后填充時的最大填充量 |
| tolerance | 向前或向后填充時,填充不準確匹配項的最大間距(絕對距離) |
| level | 在Multilndex的指定級別上匹配簡單索引,否則選取其子集 |
| copy | 默認為True,無論如何都復制;如果為False,則新舊相等就不復制 |
向前填充:
obj6 = pd.Series(['blue', 'yellow', 'orange'],index=[0,2,4])
obj6
0 blue
2 yellow
4 orange
dtype: object
obj6.reindex(range(6),method='ffill')
0 blue
1 blue
2 yellow
3 yellow
4 orange
5 orange
dtype: object
列可以用columns關鍵字重新索引:
frame2 = pd.DataFrame(np.arange(9).reshape((3,3),),
index=['a', 'c', 'd'],
columns=['Ohio', 'Texas', 'California'])
frame2
Ohio Texas California
a 0 1 2
c 3 4 5
d 6 7 8
states = ['Ohio', 'Utah', 'California']
frame2.reindex(columns=states)
Ohio Utah California
a 0 NaN 2
c 3 NaN 5
d 6 NaN 8
丟棄指定軸上的項drop函數
obj6.drop(2)
0 blue
4 orange
dtype: object
#axis=0 or axis='rows'傳遞為行(默認);axis=1 or axis='columns'傳遞為列
frame2.drop('Ohio', axis=1)
Texas California
a 1 2
c 4 5
d 7 8
#當drop函數中的參數設置為inplace=True時,就地修改對象,不會返回新的對象。必須要小心使用inplace,它會銷毀所有被刪除的數據
索引、選取和過濾
Series索引的工作方式類似于Numpy數組的索引,只不過Series的索引值不只是整數。
obj5
a -5.3
b 7.2
c 3.6
d 4.5
e NaN
dtype: float64
#利用標簽切片運算與普通的Python的切片不同,其末端是包含的
obj5['a':'c']
a -5.3
b 7.2
c 3.6
dtype: float64
#不用標簽索切片時,與Python的切片相同
obj5[:3]
a -5.3
b 7.2
c 3.6
dtype: float64
用一個值或序列對DataFrame進行索引其實就是獲取一個或多個列:
frame
state year pop add
0 Ohio 2000 0.0 1.2
1 Ohio 2001 1.0 NaN
2 Ohio 2002 2.0 NaN
3 Nevada 2001 3.0 4.3
4 Nevada 2002 4.0 NaN
5 Nevada 2003 5.0 5.7
frame[['state', 'pop']]
state pop
0 Ohio 0.0
1 Ohio 1.0
2 Ohio 2.0
3 Nevada 3.0
4 Nevada 4.0
5 Nevada 5.0
frame[1:4]
state year pop add
1 Ohio 2001 1.0 NaN
2 Ohio 2002 2.0 NaN
3 Nevada 2001 3.0 4.3
frame[frame['pop']>3]
state year pop add
4 Nevada 2002 4.0 NaN
5 Nevada 2003 5.0 5.7
用loc和iloc進行選
對于DataFrame的行的標簽索引,可以使用特殊的標簽運算符軸標簽loc和整數索引iloc。
frame.loc[3,['state', 'pop']]
state Nevada
pop 3
Name: 3, dtype: object
#iloc可以這樣理解:不管有沒有設置新的行或列索引,默認的索引都是存在的,而iloc就是提取默認的索引值。
frame.iloc[3,[0,2]]
state Nevada
pop 3
Name: 3, dtype: object
DataFrame數據選取與整合總結
| 類型 | 說明 |
|---|---|
| df[val] | 選取單列數據 |
| df.loc[val] | 通過標簽,選取DataFrame的單行數據 |
| df.loc[:,val] | 通過標簽,選取單列數據 |
| df.loc[,val1, val2] | 通過標簽,同時選取行和列對應的數據 |
| df.iloc[where] | 通過整數位置,選取單個行數據 |
| df.oloc[:, where] | 通過整數位置,選取單個列數據 |
| df.iloc[where_i, where_j] | 通過整數位置,同時選取行和列對應的數據 |
| df.at[label_i, label_j] | 通過行標簽和列標簽,選取對應的數據 |
| df.iat[i,j] | 通過行和列的位置(整數),選取對應的數據 |
| reindex | 通過標簽選取行或列 |
| get_value,set_value | 通過行和列標簽選取數據 |
算術運算和數據對齊
pandas最重要的一個功能是:對不同索引的對象進行算術運算,當數據相加時,如果存在不同索引,則結果的索引是所有數據索引的并集。
s1 = pd.Series([2,5,7,1], index=['a', 'c', 'd', 'e'])
s2 = pd.Series([1,7,9,3,4], index=['a', 'c', 'e', 'f', 'g'])
s1
a 2
c 5
d 7
e 1
dtype: int64
s2
a 1
c 7
e 9
f 3
g 4
dtype: int64
#自動的數據對齊操作在不重疊的索引處引入了NA值,對于DataFrame會同時發(fā)生在行和列上
s1 + s2
a 3.0
c 12.0
d NaN
e 10.0
f NaN
g NaN
dtype: float64
在算術方法中填充值
在對不同索引的對象進行算術運算時,我們可能希望當一個對象中某個軸標簽在另一個對象中找不到時填充一個特殊值(比如0)。此時可以使用算術方法在fill_value傳入參數0.
df1 = pd.DataFrame(np.arange(12.).reshape((3,4)),
columns=list('abcd'))
df2 = pd.DataFrame(np.arange(20.).reshape((4,5)),
columns=list('abcde'))
df1
a b c d
0 0.0 1.0 2.0 3.0
1 4.0 5.0 6.0 7.0
2 8.0 9.0 10.011.0
df2
a b c d e
0 0.0 1.0 2.0 3.0 4.0
1 5.0 6.0 7.0 8.0 9.0
2 10.011.012.013.014.0
3 15.016.017.018.019.0
df1 + df2
a b c d e
0 0.0 2.0 4.0 6.0 NaN
1 9.0 11.013.015.0NaN
2 18.020.022.024.0NaN
3 NaN NaN NaN NaN NaN
#填充值0
df1.add(df2,fill_value=0)
a b c d e
0 0.0 2.0 4.0 6.0 4.0
1 9.0 11.0 13.0 15.0 9.0
2 18.0 20.0 22.0 24.0 14.0
3 15.0 16.0 17.0 18.0 19.0
Series和DataFrame算術方法
每個算術方法都有一個副本,以字母r開頭,它會翻轉參數。兩個語句等價。
| 方法 | 說明 |
|---|---|
| add | +加 |
| sub, rsub | -減 |
| div, rdiv | /除 |
| floordiv, rfloordiv | //底除 |
| mul, rmul | *乘 |
| pow, rpow | **指數 |
DataFrame和Series之間的運算
arr = np.arange(12).reshape((3,4))
arr
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
arr[0]
array([0, 1, 2, 3])
#從arr減去arr[0],每一行都會執(zhí)行這個操作。這叫做廣播(broadcasting)
arr - arr[0]
array([[0, 0, 0, 0],
[4, 4, 4, 4],
[8, 8, 8, 8]])
#DataFrame和Series之間的運算差不多也是如此
frame3 = pd.DataFrame(np.arange(12).reshape((4,3)),
columns=list('abc'),
index=list('EMNF'))
frame3
a b c
E 0 1 2
M 3 4 5
N 6 7 8
F 9 10 11
s3 = frame3.iloc[0]
s3
a 0
b 1
c 2
Name: E, dtype: int64
frame3 - s3
a b c
E 0 0 0
M 3 3 3
N 6 6 6
F 9 9 9
如果希望在列上傳播,則必須使用算術運算方法。
s4 = frame3['a']
s4
E 0
M 3
N 6
F 9
Name: a, dtype: int64
frame3.sub(s4,axis='index')
a b c
E 0 1 2
M 0 1 2
N 0 1 2
F 0 1 2
函數應用和映射
Numpy的函數也可以用于操作pandas對象:
np.add(frame3,2)
a b c
E 2 3 4
M 5 6 7
N 8 9 10
F 11 12 13
另一個常見的操作是,將函數應用到各列或各行所形成的一維數組上。DataFrame的applay方法即可實現此功能。
frame3
a b c
E 0 1 2
M 3 4 5
N 6 7 8
F 9 10 11
f = lambda x: x.max() - x.min()
frame3.apply(f)
a 9
b 9
c 9
dtype: int64
def f(x):
return pd.Series([x.min(), x.max()], index=['min', 'max'])
frame3.apply(f, axis='columns')
min max
E 0 2
M 3 5
N 6 8
F 9 11
frame4 = pd.DataFrame(np.random.randn(4,3),
columns=list('abc'),
index=list('DEFG'))
frame4
a b c
D 0.279946 0.697885 -0.159838
E -0.890032 0.480782 1.053987
F -0.734350 -0.869877 0.439226
G 1.591106 0.822776 0.350413
#使用applymap函數得到frame4中各個浮點值的格式化字符串
f = lambda x: '%.2f' %x
frame4.applymap(f)
a b c
D 0.28 0.70 -0.16
E -0.89 0.48 1.05
F -0.73 -0.87 0.44
G 1.59 0.82 0.35
結語:有關pandas的入門介紹就寫到此,上面的筆記都是自己看《利用Python進行數據分析》第五章節(jié)的記錄,絕大部分是書中的例題,也有一小部分是自己的添加的。
參考書籍:《利用Python進行數據分析》
2019-06-13