要使用pandas,你首先就得熟悉它的两个主要数据结构:Series和DataFrame。虽然它们并不能解决所有的问题,但它们为大多数应用提供了一种可靠的、易于使用的基础。由于频繁的使用pandas、Series和DataFrame,所以我们将其引入本地命名空间中会更方便
from pandas import Series, DataFrame
import pandas as pd
Series是一种类似于一维数组的对象,它由一组数据(各种NumPy数据类型)以及一组与之相关的数据标签(即索引)组成的。仅由一组数据即可产生最简单的Series:
obj=Series([4,7,-5,3])
print(obj)
print(obj.values)
print(obj.index)
Series的字符串表现形式为:索引在左边,值在右边。由于我们没有为数据指定索引,于是会自动创建一个0到N-1(N为数据的长度)的整数型索引。你可以通过Series的values和index属性获取其数组表示形式和索引对象,输出结果如下:
0 4
1 7
2 -5
3 3
dtype: int64
[ 4 7 -5 3]
RangeIndex(start=0, stop=4, step=1)
Series与普通Numpy数组相比,可以通过索引的方式选取Series中的单个或一组值:
obj2=Series([4,7,-5,3],index=['d','b','a','c'])
print(obj2)
print(obj2['b'])
print(obj2[['a','b','c']])
输出结果:
d 4
b 7
a -5
c 3
dtype: int64
7
a -5
b 7
c 3
dtype: int64
Numpy数组运算(如根据布尔型数组进行过滤、标量乘法、应用数学函数等)都会保留索引和值之间的链接:
obj2=Series([4,7,-5,3],index=['d','b','a','c'])
print(obj2)
print(obj2[obj2>0])
print(obj2*2)
print(np.exp(obj2))
#in检索Series的index
print('b' in obj2)
输出结果:
d 4
b 7
a -5
c 3
dtype: int64
d 4
b 7
c 3
dtype: int64
d 8
b 14
a -10
c 6
dtype: int64
d 54.598150
b 1096.633158
a 0.006738
c 20.085537
dtype: float64
True
通过字典创建Series,如果只传入一个字典,则结果Series中的索引就是原字典的键(有序排列)
sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}
obj3=Series(sdata)
print(obj3)
states = ['California', 'Ohio', 'Oregon', 'Texas']
obj4=Series(sdata,index=states)
print(obj4)
输出结果
Ohio 35000
Oregon 16000
Texas 71000
Utah 5000
dtype: int64
California NaN
Ohio 35000.0
Oregon 16000.0
Texas 71000.0
dtype: float64
pandas的isnull和notnull函数可用于检测上述缺失数据,Series也有类似的实例方法:
print(pd.isnull(obj4))
print(pd.notnull(obj4))
print(obj4.isnull())
输出结果:
California True
Ohio False
Oregon False
Texas False
dtype: bool
California False
Ohio True
Oregon True
Texas True
dtype: bool
California True
Ohio False
Oregon False
Texas False
dtype: bool
Series最重要的一个功能是:它在算术运算中会自动对齐不同索引的数据
print(obj3)
print(obj4)
print(obj3+obj4)
输出结果:
Ohio 35000
Oregon 16000
Texas 71000
Utah 5000
dtype: int64
California NaN
Ohio 35000.0
Oregon 16000.0
Texas 71000.0
dtype: float64
California NaN
Ohio 70000.0
Oregon 32000.0
Texas 142000.0
Utah NaN #索引有值做加法,没值做并集
dtype: float64
Series对象本身及其索引都有一个name属性,该属性跟pandas其他的关键功能关系非常密切:
print(obj4)
obj4.name = 'population'
obj4.index.name='state'
print(obj4)
输出结果:
California NaN
Ohio 35000.0
Oregon 16000.0
Texas 71000.0
dtype: float64
state
California NaN
Ohio 35000.0
Oregon 16000.0
Texas 71000.0
Name: population, dtype: float64
Series的索引可以通过赋值的方式就地修改:
print(obj)
obj.index= ['Bob', 'Steve', 'Jeff', 'Ryan']
print(obj)
输出结果:
0 4
1 7
2 -5
3 3
dtype: int64
Bob 4
Steve 7
Jeff -5
Ryan 3
dtype: int64
DataFrame是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔值等)。DataFrame既有行索引也有列索引,它可以被看做由Series组成的字典(共用同一个索引)。跟其他类似的数据结构相比(如R的data.frame),DataFrame中面向行和面向列的操作基本上是平衡的。其实,DataFrame中的数据是以一个或多个二维块存放的(而不是列表、字典或别的一堆数据结构)。
构建DataFrame的办法有很多,最常用的一种是直接传入一个由等长列表或Numpy数组组成的字典:
data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'], 'year': [2000, 2001, 2002, 2001, 2002], 'pop': [1.5, 1.7, 3.6, 2.4, 2.9]}
frame = DataFrame(data)
print(frame)
#按指定顺序排列
print(DataFrame(data, columns=['year', 'state', 'pop']))
输出结果:
pop state year
0 1.5 Ohio 2000
1 1.7 Ohio 2001
2 3.6 Ohio 2002
3 2.4 Nevada 2001
4 2.9 Nevada 2002
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
跟Series一样,如果传入的列在数据中找不到,就会产生NA值:
data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'], 'year': [2000, 2001, 2002, 2001, 2002], 'pop': [1.5, 1.7, 3.6, 2.4, 2.9]}
frame2 = DataFrame(data, columns=['year', 'state', 'pop', 'debt'],
index=['one', 'two', 'three', 'four', 'five'])
print(frame2)
#通过类似字典标记的方式或者属性的方式,可以将DataFrame的列获取为一个Series
print(frame2['state'])
print(frame2.state)
#行也可以通过位置或名称的方式进行获取,比如用索引字段ix
print(frame2.ix['three'])
输出结果:
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
one Ohio
two Ohio
three Ohio
four Nevada
five Nevada
Name: state, dtype: object
one Ohio
two Ohio
three Ohio
four Nevada
five Nevada
Name: state, dtype: object
year 2002
state Ohio
pop 3.6
debt NaN
Name: three, dtype: object
列可以通过赋值的方式进行修改,将列表或数组赋值给某个列时,其长度必须跟DataFrame的长度相匹配,如果赋值的是一个Series,就会精确匹配DataFrame的索引。为不存在的列赋值会创建一个新列。关键字del用于删除列。
frame2['debt']=16.5
print(frame2)
frame2['debt']=np.arange(5)
print(frame2)
val = Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five'])
frame2['debt'] = val
print(frame2)
frame2['eastern'] = frame2.state == 'Ohio'
print(frame2)
#警告:Series所做的任何就地修改全部都会反映到DataFrame上
del frame2['eastern']
print(frame2)
输出结果:
year state pop debt
one 2000 Ohio 1.5 16.5
two 2001 Ohio 1.7 16.5
three 2002 Ohio 3.6 16.5
four 2001 Nevada 2.4 16.5
five 2002 Nevada 2.9 16.5
year state pop debt
one 2000 Ohio 1.5 0
two 2001 Ohio 1.7 1
three 2002 Ohio 3.6 2
four 2001 Nevada 2.4 3
five 2002 Nevada 2.9 4
year state pop debt
one 2000 Ohio 1.5 NaN
two 2001 Ohio 1.7 -1.2
three 2002 Ohio 3.6 NaN
four 2001 Nevada 2.4 -1.5
five 2002 Nevada 2.9 -1.7
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
year state pop debt
one 2000 Ohio 1.5 NaN
two 2001 Ohio 1.7 -1.2
three 2002 Ohio 3.6 NaN
four 2001 Nevada 2.4 -1.5
five 2002 Nevada 2.9 -1.7
另一种常见的数据形式是嵌套字典,外层字典的键作为列,内层键则作为行索引
pop = {'Nevada': {2001: 2.4, 2002: 2.9},'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}
frame3 = DataFrame(pop)
print(frame3)
print(frame3.T)
print(DataFrame(pop, index=[2001, 2002, 2003]))
#可以设置DataFrame的index和columns的name属性
frame3.index.name='year'
frame3.columns.name='state'
print(frame3)
#DataFrame的values属性会以二维ndarray的形式返回DataFrame中的数据
print(frame3.values)
输出结果:
Nevada Ohio
2000 NaN 1.5
2001 2.4 1.7
2002 2.9 3.6
2000 2001 2002
Nevada NaN 2.4 2.9
Ohio 1.5 1.7 3.6
Nevada Ohio
2001 2.4 1.7
2002 2.9 3.6
2003 NaN NaN
state Nevada Ohio
year
2000 NaN 1.5
2001 2.4 1.7
2002 2.9 3.6
[[ nan 1.5]
[ 2.4 1.7]
[ 2.9 3.6]]
pandas的索引对象负责管理轴标签和其他元数据(比如轴名称等)。Index对象是不可修改的(immutable),因此用户不能对其进行修改,不可修改性非常重要,因为这样才能使Index对象在多个数据结构之间安全共享,这里就不举例了。
调用Series的reindex方法将会根据新索引进行重排,如果某个索引值当前不存在,就引入缺失值或者用关键字参数fill_value指定
obj = Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c'])
obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e'])
print(obj2)
obj2=obj.reindex(['a', 'b', 'c', 'd', 'e'], fill_value=0)
print(obj2)
输出结果:
a -5.3
b 7.2
c 3.6
d 4.5
e NaN
dtype: float64
a -5.3
b 7.2
c 3.6
d 4.5
e 0.0
dtype: float64
对于时间序列这样的有序数据,重新索引时可能需要做一些插值处理,关键字参数method选项即可达到此目的。例如,使用ffill可以实现前向值填充,使用bfill实现后向填充:
obj3 = Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
print(obj3)
print(obj3.reindex(range(6), method='ffill'))
print(obj3.reindex(range(6), method='bfill'))
输出结果:
0 blue
2 purple
4 yellow
dtype: object
0 blue
1 blue
2 purple
3 purple
4 yellow
5 yellow
dtype: object
0 blue
1 purple
2 purple
3 yellow
4 yellow
5 NaN
dtype: object
丢弃指定轴上的项。丢弃某条轴上的一个或多个项很简单,只要一个索引数组或列表即可,drop方法返回的是一个在指定轴上删除了指定值的新对象。一般drop都是新生成一个对象,若使用inplace=true,则会在原对象上修改:
#Series丢弃指定轴上的项
obj = Series(np.arange(5.), index=['a', 'b', 'c', 'd', 'e'])
print(obj.drop('c'))
print(obj.drop(['d', 'c']))
#DataFrame丢弃指定轴上的项
data = DataFrame(np.arange(16).reshape((4, 4)),index=['Ohio', 'Colorado', 'Utah', 'New York'],
columns=['one', 'two', 'three', 'four'])
print(data.drop(['Colorado', 'Ohio']))
print(data.drop('two', axis=1))
print(data.drop(['two', 'four'], axis=1))
输出结果:
a 0.0
b 1.0
d 3.0
e 4.0
dtype: float64
a 0.0
b 1.0
e 4.0
dtype: float64
one two three four
Utah 8 9 10 11
New York 12 13 14 15
one three four
Ohio 0 2 3
Colorado 4 6 7
Utah 8 10 11
New York 12 14 15
one three
Ohio 0 2
Colorado 4 6
Utah 8 10
New York 12 14
索引、选取和过滤
# Series索引(obj[...])的工作方式类似于NumPy数组的索引,只不过Series的索引值不只是整数
obj = Series(np.arange(4.), index=['a', 'b', 'c', 'd'])
print(obj['b']) #obj[1]
print(obj[2:4])
print(obj[['b', 'a', 'd']])
print(obj[[1, 3]])
print(obj[obj < 2])
#如你所见,对DataFrame进行索引其实就是获取一个或多个列:
data = DataFrame(np.arange(16).reshape((4, 4)),index=['Ohio', 'Colorado', 'Utah', 'New York'],
columns=['one', 'two', 'three', 'four'])
print(data['two'])
print(data[['three', 'one']])
print(data[:2])
print(data[data['three'] > 5])
data[data < 5]=0
print(data)
print(data.ix['Colorado', ['two', 'three']])
print(data.ix[['Colorado', 'Utah'], [3, 0, 1]])
print(data.ix[data.three > 5, :3])
输出结果:
1.0
c 2.0
d 3.0
dtype: float64
b 1.0
a 0.0
d 3.0
dtype: float64
b 1.0
d 3.0
dtype: float64
a 0.0
b 1.0
dtype: float64
Ohio 1
Colorado 5
Utah 9
New York 13
Name: two, dtype: int32
three one
Ohio 2 0
Colorado 6 4
Utah 10 8
New York 14 12
one two three four
Ohio 0 1 2 3
Colorado 4 5 6 7
one two three four
Colorado 4 5 6 7
Utah 8 9 10 11
New York 12 13 14 15
one two three four
Ohio 0 0 0 0
Colorado 0 5 6 7
Utah 8 9 10 11
New York 12 13 14 15
two 5
three 6
Name: Colorado, dtype: int32
four one two
Colorado 7 0 5
Utah 11 8 9
one two three
Colorado 0 5 6
Utah 8 9 10
New York 12 13 14
算术运算和数据对齐。pandas最重要的一个功能是它可以对不同索引的对象进行算术运算。在将Series对象相加时,如果存在不同的索引对,则结果的索引就是该索引对的并集。自动的数据对齐操作在不重叠的索引处引入了NaN值。对于DataFrame,对齐操作会同时发生在行和列上。
算术运算方法有add、sub、div、mul。DataFrame和Series之间的运算。
在对不同索引的对象进行算术运算时,你可能希望当一个对象中某个轴标签在另一个对象中找不到时填充一个特殊值(比如0):
df1 = DataFrame(np.arange(12.).reshape((3, 4)), columns=list('abcd'))
df2 = DataFrame(np.arange(20.).reshape((4, 5)), columns=list('abcde'))
print(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
DataFrame和Series之间的运算。来看一个启发性的例子:
frame = DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'),index=['Utah', 'Ohio', 'Texas', 'Oregon'])
print(frame - frame.ix[0])
输出结果:
b d e
Utah 0.0 0.0 0.0
Ohio 3.0 3.0 3.0
Texas 6.0 6.0 6.0
Oregon 9.0 9.0 9.0
这就叫广播,默认情况下,DataFrame和Series之间的算术运算会将Series的索引匹配到DataFrame的列,然后沿着行一直向下广播。
如果希望在列上广播:
frame.sub(frame['d'], axis=0)
特别注意:轴用来为超过一维的数组定义的属性,二维数据拥有两个轴:第0轴沿着行的垂直往下,第1轴沿着列的方向水平延伸。如果简单点来说,就是0轴匹配的是index, 涉及上下运算;1轴匹配的是columns, 涉及左右运算。
这在数据清洗的时候是用的最多的,所以这是我把标题加粗的原因。NumPy的ufuncs(元素级数组方法)也可用于操作pandas对象:
frame = DataFrame(np.random.randn(4, 3), columns=list('bde'),
index=['Utah', 'Ohio', 'Texas', 'Oregon'])
print(frame)
print(np.abs(frame))
输出结果:
b d e
Utah -0.593021 -0.586625 0.248056
Ohio -1.181193 -0.731296 0.032435
Texas 2.097144 0.120056 0.553435
Oregon -1.291559 0.534635 0.260379
b d e
Utah 0.593021 0.586625 0.248056
Ohio 1.181193 0.731296 0.032435
Texas 2.097144 0.120056 0.553435
Oregon 1.291559 0.534635 0.260379
另一个常见的操作是,将函数应用到由各列或行所形成的一维数组上。DataFrame的apply方法即可实现此功能:
f = lambda x: x.max() - x.min()
print(frame.apply(f))
print(frame.apply(f,axis=1))
输出结果:
b 3.388703
d 1.265931
e 0.521000
dtype: float64
Utah 0.841077
Ohio 1.213628
Texas 1.977089
Oregon 1.826194
dtype: float64
许多最为常见的数组统计功能都被实现成DataFrame的方法(如sum和mean),因此无需使用apply方法。
除标量值外,传递给apply的函数还可以返回由多个值组成的Series:
def f(x):
return Series([x.min(), x.max()], index=['min', 'max'])
print(frame.apply(f))
输出结果:
b d e
min -1.268524 -0.262641 -1.020867
max 0.388243 2.310811 1.461124
此外,元素级的Python函数也是可以用的。假如你想得到frame中各个浮点值的格式化字符串,使用applymap即可:
format=lambda x:'%.2f' %x
print(frame.applymap(format))
输出结果:
b d e
Utah -0.13 -0.43 -0.29
Ohio 1.11 0.47 -0.68
Texas -1.14 -1.68 0.14
Oregon 0.27 2.15 -0.84
之所以叫做applymap,是因为Series有一个用于应用元素级函数的map方法:
frame['e'].map(format)
排序和排名
根据条件对数据集排序(sorting)也是一种重要的内置运算。
obj=Series(range(4),index=['d','a','b','c'])
print(obj.sort_index())
frame = DataFrame(np.arange(8).reshape((2, 4)), index=['three', 'one'],columns=['d', 'a', 'b', 'c'])
print(frame.sort_index(axis=1,ascending=False))
obj=Series([4,7,-3,2])
print(obj.sort_values())
#任何缺失值都会被放到Series的末尾
obj=Series([4,np.nan,7,np.nan,-3,2])
print(obj.sort_values())
输出结果:
a 1
b 2
c 3
d 0
dtype: int32
d c b a
three 0 3 2 1
one 4 7 6 5
2 -3
3 2
0 4
1 7
dtype: int64
4 -3.0
5 2.0
0 4.0
2 7.0
1 NaN
3 NaN
dtype: float64
在DataFrame上,你可能希望根据一个或多个列中的值进行排序。将一个或多个列的名字传递给by选项即可达到该目的:
frame = DataFrame({'b': [4, 7, -3, 2], 'a': [0, 1, 0, 1]})
print(frame.sort_values(by=['a', 'b']))
输出结果:
a b
2 0 -3
0 0 4
3 1 2
1 1 7
排名(ranking)跟排序关系密切,且它会增设一个排名值(从1开始,一直到数组中有效数据的数量)。它跟numpy.argsort产生的间接排序索引差不多,只不过它可以根据某种规则破坏平级关系。接下来介绍Series和DataFrame的rank方法。默认情况下,rank是通过“为各组分配一个平均排名”的方式破坏平级关系的:
obj = Series([7, -5, 7, 4, 2, 0, 4])
print(obj.rank())
print(obj.rank(method='first'))
输出结果:
0 6.5
1 1.0
2 6.5
3 4.5
4 3.0
5 2.0
6 4.5
dtype: float64
0 6.0
1 1.0
2 7.0
3 4.0
4 3.0
5 2.0
6 5.0
dtype: float64
DataFrame可以在行或列上计算排名:
frame = DataFrame({'b': [4.3, 7, -3, 2], 'a': [0, 1, 0, 1],'c': [-2, 5, 8, -2.5]})
print(frame.rank(axis=1))
输出结果:
a b c
0 2.0 3.0 1.0
1 1.0 3.0 2.0
2 2.0 1.0 3.0
3 2.0 3.0 1.0
举个例子:
df = DataFrame([[1.4, np.nan], [7.1, -4.5],[np.nan, np.nan], [0.75, -1.3]],
index=['a', 'b', 'c', 'd'],columns=['one', 'two'])
print(df.idxmax())
输出结果:
one b
two d
dtype: object
描述和汇总统计
方法 | 说明 |
count | 非NA值的数量 |
describe | 针对Series或各DataFrame列计算汇总统计 |
min、max | 计算最小值和最大值 |
argmin、argmax | 计算能够获取到最小值和最大值的索引位置(整数) |
idxmin、idxmax | 计算能够获取到最小值和最大值的索引值 |
quantile | 计算样本的分位数(0到1) |
sum | 值的总和 |
mean | 值的平均数 |
median | 值的算术中位数(50%分位数) |
mad | 根据平均值计算平均绝对离差 |
var | 样本值的方差 |
std | 样本值的标准差 |
skew | 样本值的偏度(三阶矩) |
kurt | 样本值的峰度(四阶矩) |
cumsum | 样本值的累计和 |
cummin、cummax | 样本值的累计最大值和累计最小值 |
cumprod | 样本值的累计积 |
diff | 计算一阶差分(对时间序列很有用) |
pct_change | 计算百分数变化 |
唯一值、值计数以及成员资格
unique()用于计算Series唯一值数组,value_counts()用于计算Series中各值出现的频率,isin()用于判断矢量化集合的成员资格返回布尔值。
有时,你可能希望得到DataFrame中多个相关列的一张柱状图。例如:
data = DataFrame({'Qu1': [1, 3, 4, 3, 4],'Qu2': [2, 3, 1, 2, 3],'Qu3': [1, 5, 2, 4, 4]})
result = data.apply(pd.value_counts).fillna(0)
print(result)
输出结果:
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
处理缺失数据
使用DataFrame的列
人们经常想要将DataFrame的一个或多个列当做行索引来用,或者可能希望将行索引变成DataFrame的列。以下面这个DataFrame为例:
frame = DataFrame({'a': range(7), 'b': range(7, 0, -1),'c': ['one', 'one', 'one', 'two', 'two', 'two', 'two'],
'd': [0, 1, 2, 0, 1, 2, 3]})
frame2 = frame.set_index(['c', 'd'])
print(frame2)
输出结果:
a b
c d
one 0 0 7
1 1 6
2 2 5
two 0 3 4
1 4 3
2 5 2
3 6 1
reset_index的功能跟set_index刚好相反,层次化索引的级别会被转移到列里面:
print(frame2.reset_index())
输出结果:
c d a b
0 one 0 0 7
1 one 1 1 6
2 one 2 2 5
3 two 0 3 4
4 two 1 4 3
5 two 2 5 2
6 two 3 6 1
至此,我们pandas部分的内容也结束了。