用python进行数据分析时经常要用到pandas库,为了以后便于查询,我对pandas库的两个主要数据结构Series和DataFrame的创建和使用方法进行了简单总结。
Series
从概念上说,Series是一个一维数组。但是和普通的python列表不同的是,Series支持索引。普通的python列表只能根据下标来查找特定位置的元素,而Series既可以按下标索引,也可以按照给定的keys进行索引。
1、创建Series
Series的构造函数是 Series(data, index=index, name=name)
,其中data可以是列表、numpy数组或字典,index表示要对元素进行定位的索引,默认是数字
0,1,.....
,name表示为该Series指定的名字,可以通过Series.name属性获取。
由列表创建Series:
import pandas as pd
import numpy as np
s = pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'], name='my_series')
print(s)
print(s.data)
print(s.values)
print(s.index)
print(s.name)
a 1
b 2
c 3
d 4
Name: my_series, dtype: int64
<memory at 0x0000000009504E88>
[1 2 3 4]
Index(['a', 'b', 'c', 'd'], dtype='object')
my_series
由numpy数组创建Series:
s1 = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'], name='love')
print(s1)
print(s1.name)
a 0.974985
b 0.885027
c -0.254667
d -0.248708
e -0.446959
Name: love, dtype: float64
love
需要注意的是,用python列表和numpy数组创建Series时,若指定index参数,则index的元素个数必须要与传入的data参数中的元素个数相同!index多于或少于data的元素个数都会报错!
由字典创建Series:
d = {'a': 1, 'b': 2, 'c': 3}
s2 = pd.Series(d, index=['a', 'b'])
s3 = pd.Series(d, index=['a', 'b', 'c', 'd'])
s4 = pd.Series(d)
s5 = pd.Series(d, index=[1, 2])
s6 = pd.Series(d, index=[1, 2, 3, 4])
s7 = pd.Series(d, index=['b', 'c', 'a'])
s8 = pd.Series(2, index=['a', 'b', 'c', 'd'])
print(s2)
print(s3)
print(s4)
print(s5)
print(s6)
print(s7)
print(s8)
a 1
b 2
dtype: int64
a 1.0
b 2.0
c 3.0
d NaN
dtype: float64
a 1
b 2
c 3
dtype: int64
1 NaN
2 NaN
dtype: float64
1 NaN
2 NaN
3 NaN
4 NaN
dtype: float64
b 2
c 3
a 1
dtype: int64
a 2
b 2
c 2
d 2
dtype: int64
从上面的运行结果可以知道,index的元素个数不一定要与字典中的元素个数相同!当index的元素个数较少时,将会从字典中截取一部分元素;当index元素个数较多时,将会自动保存为NAN。另外,当index中的元素与字典的keys不同时,所有的元素都会变成NAN;当index元素的顺序与keys的顺序不同时,可以改变Series中元素的储存顺序(这个skill可能在某些需要更换元素顺序的场合非常有用);当data参数为一个单一常数或变量时,所有下标都将重复这个变量。
2、Series的数据访问
访问Series既可以像访问list那样运用数组下标(包括列表切片等功能),也可以像字典一样利用keys进行索引,还可以根据某些条件对数据进行索引。
s = pd.Series(np.random.randn(6), index=['a', 'b', 'c', 'd', 'e', 'f'])
print("s[0] = ", s[0])
print("The first 3 numbers: ", s[:3])
print("Access s[0], s[2], s[4] at the same time:", s[[0, 2, 4]])
print("s['b'] = ", s['b'])
print("Access s['b'], s['e'], s['a'] at the same time:", s[['b', 'e', 'a']])
print(s > 0.5)
print(s[s > 0.5])
s[0] = 0.392929141632
The first 3 numbers: a 0.392929
b 0.603154
c 0.536006
dtype: float64
Access s[0], s[2], s[4] at the same time: a 0.392929
c 0.536006
e -0.142661
dtype: float64
s['b'] = 0.603154027249
Access s['b'], s['e'], s['a'] at the same time: b 0.603154
e -0.142661
a 0.392929
dtype: float64
a False
b True
c True
d True
e False
f False
dtype: bool
b 0.603154
c 0.536006
d 1.018407
dtype: float64
注意在同时访问 s[0], s[2], s[4]
的时候,传入的下标是一个列表 s[[0, 2, 4]]
而不是 s[0, 2, 4]
,这个在按keys进行索引访问时也一样。(s[['b', 'e', 'a']]
而不是 s['b', 'e', 'a']
);另外,留意 s > 0.5
和 s[s > 0.5]
的区别。
DataFrame
DataFrame是多个Series数组按列存储后得到的数据结构,相当于一张数据库的表(也可以看成是一张excel表)。在使用DataFrame的时候,我们应该培养自己按列存储和访问数据的直觉。
1、创建DataFrame
创建DataFrame的函数接口为DataFrame(data, index=index, columns=columns)
。其中index是行名,columns是列名,data可以是字典、二维数组等。下面分别用字典、二维数组创建DataFrame:
d = {'one': pd.Series([1, 0, 8, 7], index=['a', 'b', 'c', 'd']), 'two': pd.Series(['Jack', 'Lucy', 'Bob'], index=['a', 'b', 'c'])}
arr = [[1, 2, 3], [4, 5, 6]]
df1 = pd.DataFrame(d)
df2 = pd.DataFrame(d, index=[0, 'd', 2, 'b'], columns=['one', '2nd'])
df3 = pd.DataFrame(arr)
df4 = pd.DataFrame(arr, index=['one', 'two'], columns=['a', 'b', 'c'])
df5 = pd.DataFrame(np.random.randn(4, 3), index=['l', 'o', 'v', 'e'], columns=['Jack', 'DXM', 'forever'])
print("df1:")
print(df1)
print("df2:")
print(df2)
print("df3:")
print(df3)
print("df4:")
print(df4)
print("df5:")
print(df5)
df1:
one two
a 1 Jack
b 0 Lucy
c 8 Bob
d 7 NaN
df2:
one 2nd
0 NaN NaN
d 7.0 NaN
2 NaN NaN
b 0.0 NaN
df3:
0 1 2
0 1 2 3
1 4 5 6
df4:
a b c
one 1 2 3
two 4 5 6
df5:
Jack DXM forever
l 0.118821 -0.473873 -0.838605
o -0.974129 -0.803639 -1.474212
v 0.646528 -0.435759 -1.528049
e 1.903572 0.282889 -0.303181
也可以运用concat函数把多个Series或多个小的DataFrame拼接成一个大的DataFrame:
s1 = pd.Series([1, 2, 3, 4, 5], index=['a', 'b', 'c', 'd', 'e'])
s2 = pd.Series(np.linspace(12, 78, 5), index=['a', 'b', 'c', 'd', 'e'])
d1 = pd.DataFrame([[4, 5, 6], [7, 8, 9]], index=['one', 'two'], columns=['a', 'b', 'c'])
df6 = pd.concat([s1, s2], axis=1)
df7 = pd.concat([df4, d1], axis=1)
df8 = pd.concat([df4, d1], axis=0)
print("df6:")
print(df6)
print("df7:")
print(df7)
print("df8:")
print(df8)
df6:
0 1
a 1 12.0
b 2 28.5
c 3 45.0
d 4 61.5
e 5 78.0
df7:
a b c a b c
one 1 2 3 4 5 6
two 4 5 6 7 8 9
df8:
a b c
one 1 2 3
two 4 5 6
one 4 5 6
two 7 8 9
如上述运行结果所示,concat函数的axis参数为0时表示按行合并,为1时表示按列合并,当合并的数据为Series时,则只能按列合并。
2、DataFrame的数据访问
利用DataFrame的index、columns和values分别可以返回行名、列名和一个二维数组:
print("index: ", df5.index)
print("columns: ", df5.columns)
print("values: ")
print(df5.values)
index: Index(['l', 'o', 'v', 'e'], dtype='object')
columns: Index(['Jack', 'DXM', 'forever'], dtype='object')
values:
[[ 0.11882094 -0.47387267 -0.83860489]
[-0.97412888 -0.80363934 -1.47421162]
[ 0.64652834 -0.43575855 -1.52804869]
[ 1.90357243 0.2828892 -0.30318056]]
注意,DataFrame中是按列优先来存储数据的,访问元素时需先以列名获取对应的Series,然后再访问该Series中的某个位置的元素。获取特定某列时若该DataFrame中无列名,则可以按下标来获取列,若该DataFrame中含有列名,则必须按照列名来获取列:
df9 = pd.DataFrame(np.random.randn(6, 2))
print("df9[0]: ")
print(df9[0])
df9.columns = ['Jack', 'DXM']
print("df9[0]:")
print(df9['Jack'])
print("df9[0][2]: ", df9['Jack'][2])
df9[0]:
0 0.310104
1 -0.541683
2 -0.944970
3 0.619510
4 -0.686613
5 -0.472715
Name: 0, dtype: float64
df9[0]:
0 0.310104
1 -0.541683
2 -0.944970
3 0.619510
4 -0.686613
5 -0.472715
Name: Jack, dtype: float64
df9[0][2]: -0.944969896368
如果想要获取DataFrame中的某一行,则需要用DataFrame.iloc[]
按照下标来访问一行,也可以用DataFrame.loc[]
来按keys索引来访问一行:
df9.index = ['a', 'b', 'c', 'd', 'e', 'f']
print("df9's second row: ")
print(df9.iloc[1])
print("df9's third row: ")
print(df9.loc['c'])
df9's second row:
Jack -0.541683
DXM 0.208986
Name: b, dtype: float64
df9's third row:
Jack -0.944970
DXM 0.004729
Name: c, dtype: float64
还可以利用切片和布尔数组的方式来选取行:
print("df9's second to fifth rows:")
print(df9[1:5])
bool_index = [True, True, False, False, True, False]
print(df9[bool_index])
df9's second to fifth rows:
Jack DXM
b -0.541683 0.208986
c -0.944970 0.004729
d 0.619510 -0.300693
e -0.686613 -0.722130
Jack DXM
a 0.310104 -0.030625
b -0.541683 0.208986
e -0.686613 -0.722130
对行列进行组合获取数据:
df10 = df8[['b', 'a']].iloc[[3, 1]]
print("df10: ")
print(df10)
df10:
b a
two 8 7
two 5 4
如果需要按照行优先的形式访问DataFrame中的某个数据,可以用DataFrame.iat[]
和DataFrame.at[]
来按照下标或keys索引来访问数据:
print(df8.iat[1, 2])
print(df8.at['one', 'c'])
6
[3 6]
下面的df8.at['one', 'c']
返回两个值是因为df8中含有两行数据的名字都为’one’。需要注意的是,如果只是访问DataFrame中某个特定的元素,dataframe.at和dataframe.iat是最快的方式,这种方式与numpy二维数组的访问特定元素方式相同。