天天看點

Python資料分析之pandas的資料結構

1、Series

(1)簡介

Series是一種類似于一維數組的對象,它由一組資料(各種NumPy資料類型)以及一組與之相關的資料标簽(即索引)組成。僅由一組資料即可産生最簡單的Series:

obj = pd.Series([4,7,-5,3])

obj
Out[16]: 
0    4
1    7
2   -5
3    3
dtype: int64
           

(2)Series的字元串表現形式為:索引在左,值在右邊。

由于我們沒有為資料指定索引,于是會自動建立一個0到N-1(N為資料的長度)的整數型索引。你可以通過Series的values和index屬性擷取其數組表示形式和索引對象:

obj.values
Out[17]: array([ 4,  7, -5,  3], dtype=int64)
obj.index
Out[19]: RangeIndex(start=0, stop=4, step=1)
           

(3)通常,我們希望所建立的Series帶有一個可以對各個資料點進行标記的索引:

obj2 = pd.Series([4,7,-5,3],index=['d','F','W','f'])
obj2
Out[4]: 
d    4
F    7
W   -5
f    3
dtype: int64

obj2.index
Out[5]: Index(['d', 'F', 'W', 'f'], dtype='object')
           

與普通NumPy數組相比,你可以通過索引的方式選取Series中的單個或一組值:

obj2['d']
Out[7]: 4

obj2['d'] = 6

obj2[['d','F','W']]
Out[9]: 
d    6
F    7
W   -5
dtype: int64
           

(4)NumPy數組運算(如根據布爾型數組進行過濾、标量乘法、應用數學函數等)都會保留索引和值之間的連結:

obj2
Out[10]: 
d    6
F    7
W   -5
f    3
dtype: int64

obj2[obj2 > 0]
Out[11]: 
d    6
F    7
f    3
dtype: int64

obj2 * 2
Out[12]: 
d    12
F    14
W   -10
f     6
dtype: int64

np.exp(obj2)
Out[15]: 
d     403.428793
F    1096.633158
W       0.006738
f      20.085537
dtype: float64
           

(5)可以将Series看成是一個定長的有序字典,因為它是索引值到資料值的一個映射。它可以用在許多原本需要字典參數的函數中:

'b' in obj2
Out[16]: False

'd' in obj2
Out[17]: True
           

如果資料被存放在一個Python字典中,也可以直接通過這個字典來建立Series:

data = {'a':23,'T':45,'S':34}
obj3 = pd.Series(data)
obj3
Out[22]: 
a    23
T    45
S    34
dtype: int64
           

如果隻傳入一個字典,則結果Series中的索引就是原字典的鍵(有序排列)。

import pandas as pd
sdata = {'sa':23,'sfq':45,'dsa':75}
obj3 = pd.Series(sdata)
print(obj3)
sa     23
sfq    45
dsa    75
dtype: int64

states = ['sa','hh','dsa','sfq']
obj4 = pd.Series(sdata,index = states)
obj4
Out[4]: 
sa     23.0
hh      NaN
dsa    75.0
sfq    45.0
dtype: float64
           

在這個例子中,sdata中跟states索引相比對的那3個值會被找出來并放到相應的位置上,但由于“hh”所對應的sdata值找不到,是以其結果就為NaN(即‘not a number’,在pandas中,它用于表示缺失或NA值。在這裡會使用missing或NA表示缺失資料)。pandas的isnull和notnull函數可用于檢測缺失資料:

pd.isnull(obj4)
Out[5]: 
sa     False
hh      True
dsa    False
sfq    False
dtype: bool

pd.notnull(obj4)
Out[6]: 
sa      True
hh     False
dsa     True
sfq     True
dtype: bool
           

Series也有類似的執行個體方法:

obj4.isnull()
Out[7]: 
sa     False
hh      True
dsa    False
sfq    False
dtype: bool
           

(6)對于應用而言,Series最重要的一個功能是:它在算術運算中會自動對齊不同索引的資料。

obj3
Out[8]: 
sa     23
sfq    45
dsa    75
dtype: int64

obj4
Out[9]: 
sa     23.0
hh      NaN
dsa    75.0
sfq    45.0
dtype: float64

obj3+obj4
Out[10]: 
dsa    150.0
hh       NaN
sa      46.0
sfq     90.0
dtype: float64
           

(7)Series對象本身及其索引都有一個name屬性,該屬性跟pandas其他的關鍵功能關系非常密切:

obj4.name='population'
obj4.index.name = 'state'
obj4
Out[13]: 
state
sa     23.0
hh      NaN
dsa    75.0
sfq    45.0
Name: population, dtype: float64
           

Series的索引可以通過指派的方式就地修改:

obj4.index = ['Bob','Ss','sw','ww']        #對的
obj4.index = ['Bob','Ss','sw','ww','fwq']  #錯的,個數與原Series不符
           

2、DataFrame

(1)DataFrame簡介

DataFrame是一個表格型的資料結構,它含有一組有序的列,每列可以是不同的值類型(數值、字元串、布爾值等)。DataFrame既有行索引也有列索引,它可以被看作由Series組成的字典(共用同一個索引)。跟其他類似的資料結構相比(如R的data.frame),DataFrame中面向行和面向列的操作基本上是平衡的。其實,DataFrame中的資料是以一個或多個二維塊存放的(而不是清單、字典或别的一維資料結構)。

(2)建構DataFrame

建構DataFrame的方法有很多,最常用的一種是直接傳入一個由等長清單或NumPy數組組成的字典:

from pandas import Series,DataFrame
data = {'state':['a','b','c','d','e'],
        'year':[200,341,3432,23,43],
        'pop':[1.5,2.4,2.3,4.4,5.5]}
frame = DataFrame(data)
           

結果DataFrame會自動加上索引(跟Series一樣),且全部列會被有序排列:

frame
Out[4]: 
  state  year  pop
0     a   200  1.5
1     b   341  2.4
2     c  3432  2.3
3     d    23  4.4
4     e    43  5.5
           

如果指定了列序列,則DataFrame的列就會按照指定順序進行排列:

DataFrame(data,columns=['year','state','pop'])
Out[5]: 
   year state  pop
0   200     a  1.5
1   341     b  2.4
2  3432     c  2.3
3    23     d  4.4
4    43     e  5.5
           

(3)跟Series一樣,如果傳入的列在資料中找不到,就會産生NA值:

frame2 = DataFrame(data,columns=['year','state','pop','debt'],index=['one','two','three','four','five'])

frame2
Out[7]: 
       year state  pop debt
one     200     a  1.5  NaN
two     341     b  2.4  NaN
three  3432     c  2.3  NaN
four     23     d  4.4  NaN
five     43     e  5.5  NaN

frame2.columns
Out[8]: Index(['year', 'state', 'pop', 'debt'], dtype='object')
           

(4)通過類似字典标記的方式或屬性的方式,可以将DataFrame的列擷取為一個Series:

frame2.year
Out[9]: 
one       200
two       341
three    3432
four       23
five       43
Name: year, dtype: int64

frame2['state']
Out[10]: 
one      a
two      b
three    c
four     d
five     e
Name: state, dtype: object
           

注意,傳回的Series擁有原DataFrame相同的索引,且其name屬性也已經被相應地設定好了。

行也可以通過位置或名稱的方式進行擷取,比如用索引字段ix,沒有iy這個東東!

frame2.ix['three']
Out[11]: 
year     3432
state       c
pop       2.3
debt      NaN
Name: three, dtype: object
           

(5)列可以通過指派的方式進行修改,例如,我們可以給那個空的“debt”列賦上一個标量值或一組值:

frame2['debt']=2
frame2
Out[13]: 
       year state  pop  debt
one     200     a  1.5     2
two     341     b  2.4     2
three  3432     c  2.3     2
four     23     d  4.4     2
five     43     e  5.5     2

import numpy as np
frame2['debt'] = np.arange(5.)
frame2
Out[16]: 
       year state  pop  debt
one     200     a  1.5   0.0
two     341     b  2.4   1.0
three  3432     c  2.3   2.0
four     23     d  4.4   3.0
five     43     e  5.5   4.0
           

将清單或數組指派給某個列時,其長度必須跟DataFrame的長度相比對。如果指派的是一個Series,就會精确比對DataFrame的長度相比對。如果指派的是一個Series,就會精确比對DataFrame的索引,所有的空位都将被填上缺失值:

val = Series([-1.2,-1.5,2.3],index=['two','t','five'])    #如果設定的index中,存在和原DataFrame不相同的索引,會忽略
frame2['debt'] = val
frame2
Out[17]: 
       year state  pop  debt
one     200     a  1.5   NaN
two     341     b  2.4  -1.2
three  3432     c  2.3   NaN
four     23     d  4.4   NaN
five     43     e  5.5   2.3
           

為不存在的列指派會建立出一個新列。關鍵字del用于删除列:

frame2['eastern'] = frame2.state=='Oh'
frame2
Out[19]: 
       year state  pop  debt  eastern
one     200     a  1.5   NaN    False
two     341     b  2.4  -1.2    False
three  3432     c  2.3   NaN    False
four     23     d  4.4   NaN    False
five     43     e  5.5   2.3    False

del frame2['eastern']
frame2.columns
Out[20]: Index(['year', 'state', 'pop', 'debt'], dtype='object')
           

通過索引方式傳回的列隻是相應資料的視圖而已,并不是副本。是以對傳回的Series所做的任何就地修改全都會反映到源DataFrame上。通過Series的copy方法即可顯式地複制列。

(6)嵌套字典(字典中的字典)

pop = {'aa':{100:3,324:21},'bb':{200:1.5,201:1.7,203:4.5}}
           

如果将它傳給DataFrame,則   外層字典的鍵作為列,内層鍵則作為行索引:

frame = DataFrame(pop)
frame
Out[21]: 
       aa   bb
100   3.0  NaN
200   NaN  1.5
201   NaN  1.7
203   NaN  4.5
324  21.0  NaN
           

當然,可以對該結果進行轉置:

frame.T
Out[22]: 
    100  200  201  203   324
aa  3.0  NaN  NaN  NaN  21.0
bb  NaN  1.5  1.7  4.5   NaN
           
DataFrame(pop,index=[100,200,201,203,204])
Out[23]: 
      aa   bb
100  3.0  NaN
200  NaN  1.5
201  NaN  1.7
203  NaN  4.5
204  NaN  NaN

DataFrame(pop,columns=['aa','bb'])
Out[25]: 
       aa   bb
100   3.0  NaN
200   NaN  1.5
201   NaN  1.7
203   NaN  4.5
324  21.0  NaN
           

由Series組成的字典差不多也是一樣的用法:

pdata = {'aa':frame['aa'][:-1],
         'cc':frame['bb'][:2]}

DataFrame(pdata)
Out[27]: 
      aa   cc
100  3.0  NaN
200  NaN  1.5
201  NaN  NaN
203  NaN  NaN
           

可以輸入給DataFrame構造器的資料

二維ndarray 資料矩陣,還可以傳入行标和列标
由數組、清單或元組組成的字典 每個序列會變成DataFrame的一列。所有序列的長度必須相同
NumPy的結構化/記錄數組 類似于“由數組組成的字典”
由Series組成的字典 每個Series會成為一列。如果沒有顯示指定索引,則各Series的索引會被合并成結果的行索引
由字典組成的字典 各内層字典會成為一列。鍵會被合并成結果的行索引,跟“由Series組成的字典”的情況一樣
字典或Series的清單 各項将會成為DataFrame的一行。字典鍵或Series索引的并集将會成為DataFrame的列标
由清單或元組組成的清單 類似于“二維ndarray”
另一個DataFrame 該DataFrame的索引将會被沿用,除非顯式指定了其他索引
NumPy的MaskedArray 類似于“二維ndarray”的情況,隻是掩碼值在結果DataFrame會變成NA/缺失值

如果設定了DataFrame的index和columns的names屬性,則這些資訊也會被顯示出來:

frame.index.name = 'year'
frame.columns.name = 'state'
frame
Out[4]: 
state    aa   bb
year            
100     3.0  NaN
200     NaN  1.5
201     NaN  1.7
203     NaN  4.5
324    21.0  NaN
           

跟Series一樣,values屬性也會以二維ndarray的形式傳回DataFrame中的資料:

frame.values
Out[5]: 
array([[ 3. ,  nan],
       [ nan,  1.5],
       [ nan,  1.7],
       [ nan,  4.5],
       [21. ,  nan]])
           

如果DataFrame各列的資料類型不同,則值數組的資料類型就會選用能相容所有列的資料類型。

3、索引對象

pandas的索引對象負責管理軸标簽和其他中繼資料(比如軸名稱等)。建構Series或DataFrame時,所用到的任何數組或其他序列的标簽都會被轉換成一個Index:

obj = Series(range(3),index=['a','b','c'])
index = obj.index
index
Out[17]: Index(['a', 'b', 'c'], dtype='object')

index[1:]
Out[26]: Index(['b', 'c'], dtype='object')
           

Index對象是不可修改的(immutable),是以使用者不能對其進行修改。這樣才能使Index對象在多個資料結構之間安全共享:

index0 = pd.Index(np.arange(3))
obj2 = Series([2,3,4],index=index0)
obj2.index is index0
Out[25]: True
           

Index甚至可以被繼承進而實作特别的軸索引功能

繼續閱讀