本章主要介绍pandas数据结构和基本操作。
Numpy适合处理同质型的数值类数组数据,而 pandas是用来处理表格型或异质型数据的,经常和其他数值计算工具,比如NumPy和Scipy,以及可视化工具matplotlib一起使用的。
obj = pd.Series([4, 5, -5, 3])
obj
0 4
1 5
2 -7
3 3
dtype: int64
默认索引是从0到N-1,可以通过values和index属性分别获得Series的值和索引。
obj.values
array([ 4, 5, -7, 3], dtype=int64)
obj.index
RangeIndex(start=0, stop=4, step=1)
可以对Series设定索引格式。
obj2 = pd.Series([4, 5, -7, 3], index=["d", "b", "a", "c"])
obj2
d 4
b 5
a -7
c 3
dtype: int64
可以通过标签来进行索引取值
obj2[["b", "d", "c"]]
b 5
d 4
c 3
dtype: int64
sdata = {
'Ohio': 35000, "Texas": 71000, 'Oregon': 16000, 'Utah': 5000}
obj3 = pd.Series(sdata)
obj3
Ohio 35000
Texas 71000
Oregon 16000
Utah 5000
dtype: int64
可以将想要生成的索引传递给构造函数来生成符合预期的Series
states = ['California', 'Ohio', 'Oregon', 'Texas']
obj4 = pd.Series(sdata, index=states)
obj4
California NaN #NaN是pandas中标记缺失值或NA值的方式,可以使用isnull和notnull来检查
Ohio 35000.0
Oregon 16000.0
Texas 71000.0
dtype: float64
obj4.name = 'population'
obj4.index.name = 'state'
obj4
state
California NaN
Ohio 35000.0
Oregon 16000.0
Texas 71000.0
Name: population, dtype: float64
obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan']
obj
Bob 4
Steve 5
Jeff -7
Ryan 3
dtype: int64
表示矩阵的数据表,包含已排序的列集合,每一列可以是不同的值类型。既有行索引又有列索引,可以看作是一个共享相同索引的Series的字典。
在DataFrame中,数据被存储为一个以上的二维块,尽管DataFrame是二维的,但是可以利用分层索引在其中展现更高维度的数据。
data = {
'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(data)
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
可以指定列的顺序来进行显示,如果传的列不在字典中,则会在结果中出现缺失值
pd.DataFrame(data, columns=['year', 'state', 'pop'])
year state pop
0 2000 Ohio 1.5
1 2001 Ohio 1.7
2 2002 Ohio 3.6
3 2001 Nevada 2.4
4 2002 Nevada 2.9
5 2003 Nevada 3.2
frame2 = pd.DataFrame(data, columns=['year', 'state', 'pop', 'debt'], index=['one', 'two', 'three', 'four', 'five', 'six'])
frame2
year state pop debt
one 2000 Ohio 1.5 NaN
two 2001 Ohio 1.7 NaN
three 2002 Ohio 3.6 NaN
four 2001 Nevada 2.4 NaN
five 2002 Nevada 2.9 NaN
six 2003 Nevada 3.2 NaN
注:frame2[column]对于任意列名均有效,但是frame2.column只在列名是有效的Python变量名时有效。且frame2.column的语法无法创建新的列。
frame2['year']
frame2.year
one 2000
two 2001
three 2002
four 2001
five 2002
six 2003
Name: year, dtype: int64
行通过位置或者特殊属性loc/iloc进行选取:
frame2.loc['three']
year 2002
state Ohio
pop 3.6
debt NaN
Name: three, dtype: object
frame2['debt'] = 16.5
创建新列(不能使用frame2.eastern语法)
frame2['eastern'] = frame2.state == 'Ohio' #报警告,只能通过frame2["eastern"]来创建
frame2
year state pop debt eastern
one 2000 Ohio 1.5 NaN True
two 2001 Ohio 1.7 -1.2 True
three 2002 Ohio 3.6 NaN True
four 2001 Nevada 2.4 -1.5 False
five 2002 Nevada 2.9 -1.7 False
six 2003 Nevada 3.2 NaN False
删除某列使用del方法
del frame2['eastern']
pop = {
'Nevada': {
2001: 2.4, 2002:2.9},
"Ohio": {
2000: 1.5, 2001: 1.7, 2002: 3.6}}
frame3 = pd.DataFrame(pop)
frame3
Nevada Ohio
2001 2.4 1.7
2002 2.9 3.6
2000 NaN 1.5
frame3.T #支持转置操作
2001 2002 2000
Nevada 2.4 2.9 NaN
Ohio 1.7 3.6 1.5
pdata = {
'Ohio': frame3['Ohio'][:-1],
'Nevada': frame3["Nevada"][:2]}
pd.DataFrame(pdata)
Ohio Nevada
2001 1.7 2.4
2002 3.6 2.9
DataFrame的索引和列拥有name属性:
frame3.index.name = 'year'
frame3.columns.name = 'state'
frame3
state Nevada Ohio
year
2001 2.4 1.7
2002 2.9 3.6
2000 NaN 1.5
索引对象是不可变的,这保证了数据结构在分享索引对象时更为安全,但是数据结构的索引是可以通过命名修改的。
pandas索引对象可以包含重复标签,这点与Python集合不同,根据重复标签进行筛选会选取所有重复标签对应的数据。
Series或DataFrame中数据交互的基础机制。
a. Series调用reindex方法时,会将数据按照新的索引进行排列,如果某个索引值之前不存在,则引入缺失值。
obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=["d", "b", "a", "c"])
obj
d 4.5
b 7.2
a -5.3
c 3.6
dtype: float64
obj2 = obj.reindex(["a", "b", "c", "d", "e"])
obj2
a -5.3
b 7.2
c 3.6
d 4.5
e NaN
dtype: float64
b. 对于顺序数据,比如时间序列,在重建索引时可以进行插值或填值。对metho的可选参数ffill表示重建所以时插值 ,并且向前填充:
obj3 = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
obj3
0 blue
2 purple
4 yellow
dtype: object
obj3.reindex(range(6), method='ffill')
0 blue
1 blue
2 purple
3 purple
4 yellow
5 yellow
dtype: object
c. DataFrame中,reindex不仅能改变行索引,还可以对列索引进行更改,也可以同时改变两者。
frame = pd.DataFrame(np.arange(9).reshape((3,3)),
index = ['a', 'c', 'd'],
columns = ['Ohio', 'Texas', 'California'])
frame
Ohio Texas California
a 0 1 2
c 3 4 5
d 6 7 8
frame2 = frame.reindex(['a', 'b', 'c', 'd']) #更改行索引
frame2
Ohio Texas California
a 0.0 1.0 2.0
b NaN NaN NaN
c 3.0 4.0 5.0
d 6.0 7.0 8.0
states = ['Texas', 'Utah', "california"]
frame3 = frame.reindex(columns = states) #更改列索引,通过关键字重建索引
frame3
Texas Utah california
a 1 NaN NaN
c 4 NaN NaN
d 7 NaN NaN
obj = pd.Series(np.arange(5.), index=['a', 'b', 'c', 'd', 'e'])
obj
a 0.0
b 1.0
c 2.0
d 3.0
e 4.0
dtype: float64
new_obj = obj.drop(['c', 'd'], inplace=True) #inplace属性会清除被删除的数据。
new_obj
a 0.0
b 1.0
e 4.0
dtype: float64
frame = pd.DataFrame(np.arange(9).reshape((3,3)),
index = ['a', 'c', 'd'],
columns = ['Ohio', 'Texas', 'California'])
frame
Ohio Texas California
a 0 1 2
c 3 4 5
d 6 7 8
frame.drop(["a", "d"]) #删除行索引
Ohio Texas California
c 3 4 5
frame.drop('Ohio', axis=1) #删除列索引
Texas California
a 1 2
c 4 5
d 7 8
a. 数字型索引遵循前闭后开
obj = pd.Series(np.arange(4.), index=["a", "b", "c", "d"])
obj
a 0.0
b 1.0
c 2.0
d 3.0
dtype: float64
obj[1:3] #前闭后开
b 1.0
c 2.0
dtype: float64
b. 使用索引值来进行索引,则是前闭后闭,这点与普通的Python切片不同。
obj['b':'d'] #前闭后闭
b 1.0
c 2.0
d 3.0
dtype: float64
frame1 = pd.DataFrame(np.arange(16).reshape(4,4), index=list('abcd'), columns=list('bdac'))
frame1
b d a c
a 0 1 2 3
b 4 5 6 7
c 8 9 10 11
d 12 13 14 15
a. 对行索引:
frame1[:2] #前闭后开
b d a c
a 0 1 2 3
b 4 5 6 7
frame1["b":"d"] #前闭后闭
b d a c
b 4 5 6 7
c 8 9 10 11
d 12 13 14 15
b. 对列索引:
frame1[['a']]
a
a 2
b 6
c 10
d 14
frame1[['b', 'd']] #不支持对应的整数索引,但是iloc可以使用整数来索引
b d
a 0 1
b 4 5
c 8 9
d 12 13
c. 布尔值索引:
frame1[frame1["a"] > 5] #根据布尔值索引
b d a c
b 4 5 6 7
c 8 9 10 11
d 12 13 14 15
frame1[frame1 < 5] = 0
frame1
b d a c
a 0 0 0 0
b 0 5 6 7
c 8 9 10 11
d 12 13 14 15
a. loc使用轴标签选取数据
data = pd.DataFrame(np.arange(16).reshape((4,4)),
index = ['a',"b", 'c', 'd'],
columns = ['one', 'two', 'three', 'four'])
data
one two three four
a 0 1 2 3
b 4 5 6 7
c 8 9 10 11
d 12 13 14 15
data.loc['a']
one 0
two 1
three 2
four 3
Name: a, dtype: int32
data.loc[['b','a']] #可以根据传入的索引值顺序来设置返回的数据顺序
one two three four
b 4 5 6 7
a 0 1 2 3
data.loc[['a', 'b'], ['two', 'three']] #前面的参数是行索引,后面的为列索引
two three
a 1 2
b 5 6
data.loc[:, ['three', 'two']] #与data[['three', 'two']]返回相同数据
three two
a 2 1
b 6 5
c 10 9
d 14 13
data.loc[:'c', :'two'] #支持切片,前闭后闭
one two
a 0 1
b 4 5
c 8 9
b. iloc使用整数标签选取数据
data.iloc[2]
one 8
two 9
three 10
four 11
Name: c, dtype: int32
data.iloc[[1, 3]]
one two three four
b 4 5 6 7
d 12 13 14 15
data.iloc[1, 3] #注意与上一条语句区别
7
data.iloc[[1, 2], [3, 0, 1]]
four one two
b 7 4 5
c 11 8 9
data.iloc[:, :3] #支持切片,前闭后开
one two three
a 0 1 2
b 4 5 6
c 8 9 10
d 12 13 14
假设有一个索引,它包含了0、1、2,这样推断用户所需的索引位置可能会有歧义:
ser = pd.Series(np.arange(3))
ser
0 0
1 1
2 2
dtype: int32
ser[:1]
0 0
dtype: int32
ser.loc[:1] #注意这个1是索引值的1,而不是整数索引的1,所以是前闭后闭
0 0
1 1
dtype: int32
ser.iloc[:1]
0 0
dtype: int32
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
df1.add(df2, fill_value=0) #将不存在的索引对象填充为0然后进行add操作
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
a. 算术方法中每一个都有一个以r开头的副本,这些副本方法的参数是翻转的。
add radd / sub rsub / div rdiv / floordiv rfloordiv / mul rmul / pow rpow
b. DataFrame和Series间的算术操作与Numpy中不同维度数组间的操作类似,遵循广播机制。
frame = pd.DataFrame(np.random.randn(4, 3), columns=list('bde'),
index=['Utah', 'Ohio', 'Texas', 'Oregon'])
frame
b d e
Utah 0.806455 -0.135015 0.500107
Ohio 0.729342 -0.415839 -1.409110
Texas -2.895623 -0.815162 0.777856
Oregon -1.499056 -0.714246 -1.336805
np.abs(frame)
b d e
Utah 0.806455 0.135015 0.500107
Ohio 0.729342 0.415839 1.409110
Texas 2.895623 0.815162 0.777856
Oregon 1.499056 0.714246 1.336805
f = lambda x: x.max() - x.min()
frame.apply(f)
b 3.702078
d 0.680147
e 2.186966
dtype: float64
frame.apply(f, axis=1)
Utah 0.941470
Ohio 2.138453
Texas 3.673478
Oregon 0.784810
dtype: float64
def f(x):
return pd.Series([x.min(), x.max()], index=['min', 'max'])
frame.apply(f)
b d e
min -2.895623 -0.815162 -1.409110
max 0.806455 -0.135015 0.777856
逐元素的Python函数也可以使用,可以使用applymap方法:
format_f = lambda x: '%.2f' % x
frame.applymap(format_f)
b d e
Utah 0.81 -0.14 0.50
Ohio 0.73 -0.42 -1.41
Texas -2.90 -0.82 0.78
Oregon -1.50 -0.71 -1.34
frame['e'].map(format_f) #对于Series则有对应的map方法也可以使用
Utah 0.50
Ohio -1.41
Texas 0.78
Oregon -1.34
Name: e, dtype: object
根据某些准则进行排序是另一个重要的内建操作。
a. 如需按行或者列索引进行排序,可以使用sort_index方法,该方法返回一个新的、排序好的对象:
frame = pd.DataFrame(np.arange(8).reshape((2,4)), index=['three', 'one'], columns=list('dabc'))
frame
d a b c
three 0 1 2 3
one 4 5 6 7
frame.sort_index() #按行索引排序
d a b c
one 4 5 6 7
three 0 1 2 3
frame.sort_index(axis=1) #按列索引排序
a b c d
three 1 2 3 0
one 5 6 7 4
frame.sort_index(axis=1, ascending=False) #降序排列
d c b a
three 0 3 2 1
one 4 7 6 5
b. 根据Series的值进行排序,使用sort_values方法:
obj = pd.Series([4, np.nan, 7, np.nan, -3, 2])
obj
0 4.0
1 NaN
2 7.0
3 NaN
4 -3.0
5 2.0
dtype: float64
obj.sort_values() #默认情况下,所有的缺失值都会被排序至尾部
4 -3.0
5 2.0
0 4.0
2 7.0
1 NaN
3 NaN
dtype: float64
c. DataFrame排序时可以使用一列或多列作为排序键:
frame = pd.DataFrame({
'b': [4, 7, -3, 2],
'a': [0, 1, 0, 1]})
frame
b a
0 4 0
1 7 1
2 -3 0
3 2 1
frame.sort_values('b')
b a
2 -3 0
3 2 1
0 4 0
1 7 1
frame.sort_values(by=['a', 'b'])
b a
2 -3 0
0 4 0
3 2 1
1 7 1
排名是指数组从1到有效数据点总数分配名次的操作。Series和DataFrame的rank方法是实现排名的方法,且支持多种不同的排名方式。
a = pd.Series([1,2,2,2,3,5,6,3,4])
rank_a = pd.DataFrame()
rank_a['base'] = a
rank_a['average'] = a.rank(method='average') # 默认,在每个组中分配平均排名(组,相同的值就是一个组)
rank_a['min'] = a.rank(method='min') # 对整个组使用最小排名
rank_a['first'] = a.rank(method='first') # 按照值在数据中出现的次序分配排名
rank_a['max'] = a.rank(method='max') # 对整个组使用最大排名
rank_a['dense'] = a.rank(method='dense') # 类似于‘min’,但是组间排名总是增加1,而不是相等元素的数量
rank_a
base average min first max dense
0 1 1.0 1.0 1.0 1.0 1.0
1 2 3.0 2.0 2.0 4.0 2.0
2 2 3.0 2.0 3.0 4.0 2.0
3 2 3.0 2.0 4.0 4.0 2.0
4 3 5.5 5.0 5.0 6.0 3.0
5 5 8.0 8.0 8.0 8.0 5.0
6 6 9.0 9.0 9.0 9.0 6.0
7 3 5.5 5.0 6.0 6.0 3.0
8 4 7.0 7.0 7.0 7.0 4.0
索引的is_unique属性可以查看数据标签是否唯一:
obj = pd.Series(range(5), index=['a', 'a', 'b', 'b', 'c'])
obj
a 0
a 1
b 2
b 3
c 4
dtype: int64
obj.index.is_unique
False
pandas装配的常用数学、统计学方法的集合可以从DataFrame的行或列中抽取一个Series或一系列值的单个值(如总和或平均值)。
df = pd.DataFrame([[1.4, np.nan], [7.1, -4.5], [np.nan, np.nan], [0.75, -1.3]],
index=list('abcd'), columns=['one', 'two'])
df
one two
a 1.40 NaN
b 7.10 -4.5
c NaN NaN
d 0.75 -1.3
df.mean()
one 3.083333 # (1.40+7.10+0.75)/3
two -2.900000
dtype: float64
df.mean(axis=1) #除非整行或整列都是NA,否则NA值是被自动排除的。
a 1.400
b 1.300
c NaN
d -0.275
dtype: float64
a. 可以通过skipna来实现不排除NA值:
df.mean(skipna=False)
one NaN
two NaN
dtype: float64
df.mean(axis=1, skipna=False)
a NaN
b 1.300
c NaN
d -0.275
dtype: float64
b. 常用描述性统计和汇总统计
df.cumsum()
one two
a 1.40 NaN
b 8.50 -4.5
c NaN NaN
d 9.25 -5.8
df.describe()
one two
count 3.000000 2.000000
mean 3.083333 -2.900000
std 3.493685 2.262742
min 0.750000 -4.500000
25% 1.075000 -3.700000
50% 1.400000 -2.900000
75% 4.250000 -2.100000
max 7.100000 -1.300000
c. 相关性和协方差
Series的corr方法计算的是两个Series中重叠的、非NA的、按索引对齐的值的相关性。cov是协方差。
DataFrame的corr和cov方法会分别以DataFrame的形式返回相关性和协方差矩阵。
returns = price.pct_change()
returns.tail()
AAPL IBM MSFT GOOG
Date
2020-02-10 0.004750 0.006649 0.026157 0.019909
2020-02-11 -0.006033 -0.006152 -0.022575 0.000073
2020-02-12 0.023748 0.011923 0.001464 0.006283
2020-02-13 -0.007121 -0.006439 -0.005414 -0.002378
2020-02-14 0.000246 -0.023394 0.008927 0.004014
returns['MSFT'].corr(returns['IBM'])
0.4675467304315449
returns['MSFT'].cov(returns['IBM'])
8.800905589421394e-05
returns.corr()
AAPL IBM MSFT GOOG
AAPL 1.000000 0.387745 0.584929 0.531989
IBM 0.387745 1.000000 0.467547 0.404837
MSFT 0.584929 0.467547 1.000000 0.670882
GOOG 0.531989 0.404837 0.670882 1.000000
returns.cov()
AAPL IBM MSFT GOOG
AAPL 0.000242 0.000079 0.000131 0.000125
IBM 0.000079 0.000170 0.000088 0.000080
MSFT 0.000131 0.000088 0.000208 0.000146
GOOG 0.000125 0.000080 0.000146 0.000227
DataFrame的corrwith方法:
returns.corrwith(returns.IBM)
AAPL 0.387745
IBM 1.000000
MSFT 0.467547
GOOG 0.404837
dtype: float64
d. 唯一值、计数和成员属性
常用方法:isin / match / unique / value_counts
data = pd.DataFrame({
'Qu1': [1, 3, 4, 3, 4],
'Qu2': [2, 3, 1, 2, 3],
'Qu3': [1, 5, 2, 4, 4]})
data
Qu1 Qu2 Qu3
0 1 2 1
1 3 3 5
2 4 1 2
3 3 2 4
4 4 3 4
result = data.apply(pd.value_counts)
result # 行标签是所有列中出现的不同值,数值则是这些不同的值在每个列中出现的次数
Qu1 Qu2 Qu3
1 1.0 1.0 1.0
2 NaN 2.0 1.0
3 2.0 2.0 NaN
4 2.0 NaN 2.0
5 NaN NaN 1.0
result1 = data.apply(pd.value_counts).fillna(0)
result1
Qu1 Qu2 Qu3
1 1.0 1.0 1.0
2 0.0 2.0 1.0
3 2.0 2.0 0.0
4 2.0 0.0 2.0
5 0.0 0.0 1.0