Pandas入门 ¶
约定:
import numpy as np
import pandas as pd
from pandas import Series, DataFrame
import pandas_datareader as web
pandas数据结构介绍 ¶
Series ¶
Series是一种一维的数组型对象,它包含了一个值序列(与NumPy中的类型相似),并且包含了数据标签,称为**索引(index)。 从另一个角度考虑Series,可以认为它是一个**长度固定且有序的字典,因为它将索引值和数据值按位置配对。索引在左边,值在右边。
obj = pd.Series([4, 7, -5, 3])
print(obj)
# 0 4
# 1 7
# 2 -5
# 3 3
# dtype: int64
print(obj.values)
# [ 4 7 -5 3
print(obj.index)
# RangeIndex(start=0, stop=4, step=1)
自定义index
obj = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c'])
print(obj)
# d 4
# b 7
# a -5
# c 3
# dtype: int64
print(obj.values)
# [ 4 7 -5 3]
print(obj.index)
# Index(['d', 'b', 'a', 'c'], dtype='object')
# 输出索引值为'a'的Series值
print(obj['a'])
# -5
# 使用布尔值数组进行过滤Series值
print(obj[obj > 3])
# d 4
# b 7
# dtype: int64
# 对Series值进行算术运算
print(obj * 2)
# d 8
# b 14
# a -10
# c 6
# dtype: int64
# 对Series值进行算术运算
print(np.exp(obj))
# d 54.598150
# b 1096.633158
# a 0.006738
# c 20.085537
# dtype: float64
# 更新Series数组值
obj['a'] = 9
# 输出指定索引值的Series值,注意,索引条件是列表
print(obj[['a', 'b', 'c']])
# a 9
# b 7
# c 3
# dtype: int64
# 注意,下面的判断是索引值,非Series值
print(obj)
print(7 in obj)
# False
print('a' in obj)
# True
通过字典生成一个Series。NaN
(not a number),这是pandas中标记缺失值或NA值的方式。
当把字典传递给Series构造函数时,产生的Series的索引将是排序好的字典键。可以将字典键按照你所想要的顺序传递给构造函数,从而使生成的Series的索引顺序符合预期。
看下例,通过字典sdata生成Series。
sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}
obj3 = pd.Series(sdata)
print(sdata)
# {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}
print(obj3)
# Ohio 35000
# Texas 71000
# Oregon 16000
# Utah 5000
# dtype: int64
通过指定索引states去匹配字典sdata生成基于新索引states的Series。
states = ['California', 'Ohio', 'Oregon', 'Texas']
obj4 = pd.Series(sdata, index=states)
print(obj4)
# California NaN
# Ohio 35000.0
# Oregon 16000.0
# Texas 71000.0
# dtype: float64
对Series进行布尔值判断。
print(pd.isnull(obj4))
# California True
# Ohio False
# Oregon False
# Texas False
# dtype: bool
print(pd.notnull(obj4))
# California False
# Ohio True
# Oregon True
# Texas True
# dtype: bool
对Series进行布尔值判断。
print(obj4.isnull)
# <bound method Series.isnull of California NaN
# Ohio 35000.0
# Oregon 16000.0
# Texas 71000.0
# dtype: float64>
print(obj4.notnull)
# <bound method Series.notnull of California NaN
# Ohio 35000.0
# Oregon 16000.0
# Texas 71000.0
# dtype: float64>
Series的自动对齐索引,与数据库的join操作是非常相似。
print("obj3 \n", obj3)
# obj3
# Ohio 35000
# Texas 71000
# Oregon 16000
# Utah 5000
# dtype: int64
print("obj4 \n", obj4)
# obj4
# California NaN
# Ohio 35000.0
# Oregon 16000.0
# Texas 71000.0
# dtype: float64
print("obj3+obj4 \n", obj3 + obj4)
# obj3+obj4
# California NaN
# Ohio 70000.0
# Oregon 32000.0
# Texas 142000.0
# Utah NaN
# dtype: float64
# 下面是obj3和obj4的值,帮助理解上面obj3 + obj4的操作。
# obj3 obj4
# Ohio 35000 California NaN
# Texas 71000 Ohio 35000.0
# Oregon 16000 Oregon 16000.0
# Utah 5000 Texas 71000.0
# dtype: int64 dtype: float64
Series对象自身和其索引都有name属性。
obj4.name = 'population'
obj4.index.name = 'state'
print(obj4)
# state
# California NaN
# Ohio 35000.0
# Oregon 16000.0
# Texas 71000.0
# Name: population, dtype: float64
替换Series的索引名。
obj = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c'])
print(obj)
obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan']
print(obj)
# Bob 4
# Steve 7
# Jeff -5
# Ryan 3
# dtype: int64
DataFrame ¶
DataFrame表示的是矩阵的数据表,它包含已排序的列集合,每一列可以是不同的值类型(数值、字符串、布尔值等)。
DataFrame既有行索引也有列索引,它可以被视为一个共享相同索引的Series的字典,比如所有列共享同一个列索引。
在DataFrame中,数据被存储为一个以上的二维块,而不是列表、字典或其他一维数组的集合。
DataFrame是二维的,但可以利用**分层索引**在DataFrame中展现更高维度的数据。
从DataFrame中选取的列是数据的视图,而不是拷贝。因此,对Series的修改会映射到DataFrame中。如果需要复制,则应当显式地使用Series的copy方法。
由字典构成DataFrame ¶
基于字典data
产生的DataFrame会自动为Sereies分配索引,并且列会按照排序的顺序排列。
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)
print(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, head方法将会只选出头部的若干行, 默认是前五行。
print(frame.head(3))
# state year pop
# 0 Ohio 2000 1.5
# 1 Ohio 2001 1.7
# 2 Ohio 2002 3.6
如果指定了列的顺序,DataFrame的列将会按照指定顺序排列。
frame = pd.DataFrame(data, columns=['year', 'state', 'pop'])
print(frame)
# 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
如果传的列(debt
)不包含在字典(data
)中,将会在结果中出现缺失值。
frame2 = pd.DataFrame(
data,
columns=['year', 'state', 'pop', 'debt'],
index=['one', 'two', 'three', 'four', 'five', 'six']
)
print(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
选取行, 可以通过位置或行索引标签loc
进行选取。
print(frame2.loc['three'])
# year 2002
# state Ohio
# pop 3.6
# debt NaN
# Name: three, dtype: object
DataFrame中的一列,可以按字典型标记或属性那样检索为Series。 frame2[colunm]
对于任意列名均有效,但是frame2.column
只在列名是有效的Python变量名时有效。 返回的Series与原DataFrame有相同的索引,且Series的name
属性也会被合理地设置。
print(frame2['state'])
# one Ohio
# two Ohio
# three Ohio
# four Nevada
# five Nevada
# six Nevada
# Name: state, dtype: object
print(frame2.state) # 属性型连接
# one Ohio
# two Ohio
# three Ohio
# four Nevada
# five Nevada
# six Nevada
# Name: state, dtype: object
列的引用是可以修改的。值的长度必须和DataFrame的长度相匹配,比如,下例中np.arange(6.)
和frame2['debt']
的长度都是6。
frame2['debt'] = 16.5
print(frame2)
# Name: state, dtype: object
# 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
# six 2003 Nevada 3.2 16.5
frame2['debt'] = np.arange(6.)
print(frame2)
# year state pop debt
# one 2000 Ohio 1.5 0.0
# two 2001 Ohio 1.7 1.0
# three 2002 Ohio 3.6 2.0
# four 2001 Nevada 2.4 3.0
# five 2002 Nevada 2.9 4.0
# six 2003 Nevada 3.2 5.0
如果将Series赋值给一列时,Series的索引将会按照DataFrame的索引重新排列,并在空缺的地方填充缺失值
val = pd.Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five'])
frame2['debt'] = val
print(frame2)
# 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
# six 2003 Nevada 3.2 NaN
如果被赋值的列(eastern
列)并不存在,则会生成一个新的列。frame2.state == 'Ohio'
返回的是布尔值,赋值给eastern
。
frame2['eastern'] = frame2.state == 'Ohio'
print(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
print(frame2.eastern)
# one True
# two True
# three True
# four False
# five False
# six False
# Name: eastern, dtype: bool
del
关键字可以像在字典中那样对DataFrame删除列。
del frame2['eastern']
print(frame2.columns)
# Index(['year', 'state', 'pop', 'debt'], dtype='object')
使用嵌套字典构建DataFrame ¶
pandas会将字典的键作为列('Nevada', etc.),将内部字典的键作为行索引(2001, etc.)
pop = {
'Nevada': {
2001: 2.4,
2002: 2.9
},
'Ohio': {
2000: 1.5,
2001: 1.7,
2002: 3.6
}
}
# 不指定索引,默认使用字典索引
frame3 = pd.DataFrame(pop)
print(frame3)
# Nevada Ohio
# 2001 2.4 1.7
# 2002 2.9 3.6
# 2000 NaN 1.5
# 指定字典某列作为索引
print(pd.DataFrame(pop, index=[2001, 2002, 2003]))
# Nevada Ohio
# 2001 2.4 1.7
# 2002 2.9 3.6
# 2003 NaN NaN
# 指定不相干索引
print(pd.DataFrame(pop, index=['a', 'b', 'c']))
# Nevada Ohio
# a NaN NaN
# b NaN NaN
# c NaN NaN
转置操作(调换行和列)
print(frame3.T)
# 2001 2002 2000
# Nevada 2.4 2.9 NaN
# Ohio 1.7 3.6 1.5
使用含Series的字典构造DataFrame ¶
frame3['Ohio'][:-1]
是值为Ohio
的Series的0~倒数第一个元素(不含),一共3个。 frame3['Nevada'][:2]
是值为Nevada
的Series的前2个元素。
pdata = {
'Ohio': frame3['Ohio'][:-1],
'Nevada': frame3['Nevada'][:2]
}
print(pd.DataFrame(pdata))
# Ohio Nevada
# 2001 1.7 2.4
# 2002 3.6 2.9
指定Dataframe frame3
的列名。
frame3.index.name = 'year'
frame3.columns.name = 'state'
print(frame3)
# state Nevada Ohio
# year
# 2001 2.4 1.7
# 2002 2.9 3.6
# 2000 NaN 1.5
只输出Dataframe的值frame3.values
,是一个二维数组。
print(frame3.values)
# [[2.4 1.7]
# [2.9 3.6]
# [nan 1.5]]
只输出Dataframe的值frame2.values
,是一个二维数组。
print(frame2)
# 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
# six 2003 Nevada 3.2 NaN
print(frame2.values)
# [[2000 'Ohio' 1.5 nan]
# [2001 'Ohio' 1.7 -1.2]
# [2002 'Ohio' 3.6 nan]
# [2001 'Nevada' 2.4 -1.5]
# [2002 'Nevada' 2.9 -1.7]
# [2003 'Nevada' 3.2 nan]]
索引对象 ¶
pandas中的**索引对象**是用于存储轴标签和其他元数据的(例如轴名称或标签)。
在构造Series或DataFrame时,你所使用的任意数组或标签序列都可以在内部转换为索引对象。 索引对象是不可变的。
除了类似数组,索引对象也像一个固定大小的集合。与Python集合不同,pandas索引对象可以包含重复标签。 因为一些操作会产生包含索引化数据的结果,理解索引如何工作还是很重要的。
下例演示了如何读取Dataframe的索引值。
obj = pd.Series(range(3), index=['a', 'b', 'c'])
index = obj.index
print(obj)
# a 0
# b 1
# c 2
# dtype: int64
print(index)
# Index(['a', 'b', 'c'], dtype='object')
print(index[1:])
# Index(['b', 'c'], dtype='object')
下例演示了通过一个指定的Dataframe索引labels
来生成Dataframe obj2
。
labels = pd.Index(np.arange(3))
print(labels)
# Int64Index([0, 1, 2], dtype='int64')
obj2 = pd.Series([1.5, -2.5, 0], index=labels)
print(obj2)
# 0 1.5
# 1 -2.5
# 2 0.0
# dtype: float64
print(obj2.index is labels)
# True
下例演示了不指定索引,默认使用字典索引来创建Dataframe。
pop = {
'Nevada': {
2001: 2.4,
2002: 2.9
},
'Ohio': {
2000: 1.5,
2001: 1.7,
2002: 3.6
}
}
frame3 = pd.DataFrame(pop)
print(frame3)
# Nevada Ohio
# 2001 2.4 1.7
# 2002 2.9 3.6
# 2000 NaN 1.5
print(frame3)
# state Nevada Ohio
# year
# 2001 2.4 1.7
# 2002 2.9 3.6
# 2000 NaN 1.5
print(frame3.columns)
# Index(['Nevada', 'Ohio'], dtype='object', name='state')
print(frame3.index)
# Int64Index([2001, 2002, 2000], dtype='int64', name='year')
print('Ohio' in frame3.columns)
# True
print(2003 in frame3.index)
# False
pandas索引对象允许包含重复标签。根据重复标签进行筛选,会选取所有重复标签对应的数据。
dup_labels = pd.Index(['foo', 'foo', 'bar', 'bar'])
print(dup_labels)
# Index(['foo', 'foo', 'bar', 'bar'], dtype='object')
一些常用索引对象的方法和属性。
obj1 = pd.Series(range(3), index=['a', 'b', 'c'])
index1 = obj1.index
obj2 = pd.Series(range(3), index=['c', 'f', 'g'])
index2 = obj2.index
print(index1)
# Index(['a', 'b', 'c'], dtype='object')
print(index2)
# Index(['c', 'f', 'g'], dtype='object')
append
方法:将外部的索引对象粘贴到原索引后,产生一个新的索引。 接上例,把index2
对象追加到index1
对象。
print(index1.append(index2))
# Index(['a', 'b', 'c', 'c', 'f', 'g'], dtype='object')
difference
方法: 计算2个索引的差集。
print(index1.difference(index2))
# Index(['a', 'b'], dtype='object')
intersection
方法: 计算2个索引的交集。
print(index1.intersection(index2))
# Index(['c'], dtype='object')
union
方法: 计算2个索引的并集(去重)。
print(index1.union(index2))
# Index(['a', 'b', 'c', 'f', 'g'], dtype='object')
isin
方法: 计算表示每一个值是否在传值容器中,返回的是一个布尔数组。
print(index1.isin(index2))
# [False False True]
delete
方法: 将位置i(从0开始编号)的元素删除,并产生新的索引。
print(index1.delete('b'))
# IndexError: arrays used as indices must be of integer (or boolean) type
print(index1.delete(1))
# Index(['a', 'c'], dtype='object')
print(index1)
# Index(['a', 'b', 'c'], dtype='object')
drop
方法: 根据传参删除指定索引值,并产生新的索引, 对比和delete的区别,delete
方法是输入位置,drop
方法是输入索引名称。
print(index2.drop(1))
# KeyError: '[1] not found in axis'
print(index2.drop('f'))
# Index(['c', 'g'], dtype='object')
print(index2)
# Index(['c', 'f', 'g'], dtype='object')
insert
方法: 在位置i
插入元素,并产生新的索引。
print(index1.insert(1, 'e'))
# Index(['a', 'e', 'b', 'c'], dtype='object')
print(index1)
# Index(['a', 'b', 'c'], dtype='object')
is_monotonic
方法: 如果索引序列递增,则返回True
。
print(index1.is_monotonic)
# True
print(index1.insert(1, 'e').is_monotonic)
# False
is_unique
方法: 如果索引序列唯一则返回True
。
print(index1.is_unique) # True
print(index1.append(index2).is_unique) # False
unique
方法: 计算索引的唯一值序列(对比Union)。
print(index1.unique())
# Index(['a', 'b', 'c'], dtype='object')
print(index1.append(index2).unique())
# Index(['a', 'b', 'c', 'f', 'g'], dtype='object')
pandas基本功能 ¶
重建索引 ¶
Series调用reindex
方法时,会将数据按照新的索引进行排列,如果某个索引值之前并不存在,则会引入缺失值。 下例中,对obj1
做reindex
,reindex
方法会创建一个新索引对象obj2
,索引值e
之前并不存在,所以填入缺失值。 如果对obj1做reindex
时指定method='ffill'
,会报错index must be monotonic increasing or decreasing
。
obj1 = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c'])
print(obj1)
# d 4.5
# b 7.2
# a -5.3
# c 3.6
# dtype: float64
obj2 = obj1.reindex(['a', 'b', 'c', 'd', 'e'])
print(obj2)
# a -5.3
# b 7.2
# c 3.6
# d 4.5
# e NaN
# dtype: float64
obj2 = obj1.reindex(['a', 'b', 'c', 'd', 'e'], method='ffill')
# ValueError: index must be monotonic increasing or decreasing
对于顺序数据,比如时间序列,在重建索引时可能会需要进行插值或填值。ffill
方法在重建索引时插值,将值前向填充。
obj3 = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
print(obj3.reindex(range(6), method='ffill'))
# 0 blue
# 1 blue
# 2 purple
# 3 purple
# 4 yellow
# 5 yellow
# dtype: object
在DataFrame中,reindex
可以改变行索引、列索引,也可以同时改变二者。当仅传入一个序列时,会重建行索引。 下例中,通过indexes
创建Dataframe frame
。 通过frame.reindex(['a', 'b', 'c', 'd'])重建行索引
。 通过frame2.reindex(columns=['Ohio', 'Uta', 'California'])
重建列索引。 缺失的索引列填入缺失值。
indexes = index = ['a', 'b', 'c']
states = ['Ohio', 'Texas', 'California']
frame = pd.DataFrame(
np.arange(9).reshape(3, 3),
index=indexes,
columns=states
)
print(frame)
# Ohio Texas California
# a 0 1 2
# b 3 4 5
# c 6 7 8
frame2 = frame.reindex(['a', 'b', 'c', 'd']) # 重建行索引
print(frame2)
# Ohio Texas California
# a 0.0 1.0 2.0
# b 3.0 4.0 5.0
# c 6.0 7.0 8.0
# d NaN NaN NaN
frame3 = frame2.reindex(columns=['Ohio', 'Uta', 'California']) # 重建列索引
print(frame3)
# Ohio Uta California
# a 0.0 NaN 2.0
# b 3.0 NaN 5.0
# c 6.0 NaN 8.0
# d NaN NaN NaN
使用loc
进行更为简洁的行、列标签索引。下例通过筛选行索引和列索引产生新的Dataframe。
frame4 = frame.loc[['a', 'b'], states]
print(frame4)
# Ohio Texas California
# a 0 1 2
# b 3 4 5
轴向索引删除条目 ¶
set_index()
, dropna()
, fillna()
, reset_index()
, drop()
, replace()
这些方法的inplace
属性设为True
时,这些方法会修改Series或DataFrame的尺寸或形状,*直接*操作原对象而不返回新对象。
obj = pd.Series(np.arange(5), index=['a', 'b', 'c', 'd', 'e'])
print(obj)
# a 0
# b 1
# c 2
# d 3
# e 4
# dtype: int64
obj1 = obj.drop('c')
print(obj1)
# a 0
# b 1
# d 3
# e 4
# dtype: int64
print(obj1.drop(['d', 'e']))
# a 0
# b 1
# dtype: int64
对比inplace=True
和False
的区别。inplace=False
时,obj
的值没有变化。
obj = pd.Series(np.arange(5), index=['a', 'b', 'c', 'd', 'e'])
print(obj.drop('c', inplace=False)) # 说明生成了新对象
# a 0
# b 1
# d 3
# e 4
# dtype: int64
print(obj)
# a 0
# b 1
# c 2
# d 3
# e 4
# dtype: int64
obj.drop('c', inplace=True)
输出是None
,说明没有生成新对象,变化直接作用到obj
上。
obj = pd.Series(np.arange(5), index=['a', 'b', 'c', 'd', 'e'])
print(obj)
print(obj.drop('c', inplace=True)) # 说明没有生成新对象
# None
print(obj)
# a 0
# b 1
# d 3
# e 4
# dtype: int64
下例演示了轴向的效果。 如果不指定轴向axis,drop()
会默认沿axis=0
进行,所以,在0轴上执行data.drop(['one', 'two'])
会报错。 axis='columns
与指定axis=1
同样效果。
data = pd.DataFrame(
np.arange(16).reshape(4, 4),
index=['Ohio', 'Colorado', 'Utah', 'New York'],
columns=['one', 'two', 'three', 'four']
)
print(data)
# one two three four
# Ohio 0 1 2 3
# Colorado 4 5 6 7
# Utah 8 9 10 11
# New York 12 13 14 15
# 沿0轴操作,删除符合条件的行记录
print(data.drop(['Ohio', 'Colorado']))
# one two three four
# Utah 8 9 10 11
# New York 12 13 14 15
print(data.drop(['one', 'two']))
# KeyError: "['one' 'two'] not found in axis"
# 沿1轴操作,删除符合条件的列记录
print(data.drop(['one', 'two'], axis=1))
# three four
# Ohio 2 3
# Colorado 6 7
# Utah 10 11
# New York 14 15
print(data.drop(['one', 'two'], axis='columns'))
# three four
# Ohio 2 3
# Colorado 6 7
# Utah 10 11
# New York 14 15
再通过下例体会一下inplace
参数的不同效果。
data = pd.DataFrame(
{
'Name': ['Shobhit', 'vaibhav', 'vimal', 'Sourabh'],
'class': [11, 12, 10, 9],
'Age': [18, 20, 21, 17]
}
)
print(data)
# Name class Age
# 0 Shobhit 11 18
# 1 vaibhav 12 20
# 2 vimal 10 21
# 3 Sourabh 9 17
print(data.rename(columns={'Name': 'FirstName'}, inplace=False))
# FirstName class Age
# 0 Shobhit 11 18
# 1 vaibhav 12 20
# 2 vimal 10 21
# 3 Sourabh 9 17
print(data)
# Name class Age
# 0 Shobhit 11 18
# 1 vaibhav 12 20
# 2 vimal 10 21
# 3 Sourabh 9 17
print(data.rename(columns={'Name': 'FirstName'}, inplace=True)) # 没有生成新对象
# None
print(data)
# FirstName class Age
# 0 Shobhit 11 18
# 1 vaibhav 12 20
# 2 vimal 10 21
# 3 Sourabh 9 17
索引、选择与过滤 ¶
Series的索引obj[...]
与NumPy数组索引的功能类似,只不过Series的索引值可以不仅仅是整数。
下例中:
obj[1]
通过索引位1
检索,输出对应Series的值。obj[1]
通过索引位[1]
检索,输出Series。obj['b']
通过索引值'b'
检索,输出对应Series的值。obj[['b']]
通过索引值['b']
检索,输出Series。
obj = pd.Series(['Shobhit', 'vaibhav', 'vimal', 'Sourabh'], index=['a', 'b', 'c', 'd'])
print(obj)
# a Shobhit
# b vaibhav
# c vimal
# d Sourabh
# dtype: object
print(obj[1]) # 通过索引位检索,输出对应Series的值
# vaibhav
print(obj[[1]])
# b vaibhav
# dtype: object
print(obj['b']) # 通过索引值检索,输出对应Series的值
# vaibhav
print(obj[['b']]) # 通过索引值检索,输出Series
# b vaibhav
# dtype: object
下面一组的输出中,注意对比普通Python切片与Series的切片的差异。
obj = pd.Series(['Shobhit', 'vaibhav', 'vimal', 'Sourabh'], index=['a', 'b', 'c', 'd'])
print(obj[1])
# vaibhav
print(obj[[1]])
# b vaibhav
# dtype: object
print(obj[1:3])
# b vaibhav
# c vimal
# dtype: object
print(obj['b':'d'])
# b vaibhav
# c vimal
# d Sourabh
# dtype: object
Series的切片的值更新。 obj['b': 'c'] = 5
是通过索引值进行更新,直接作用在obj
。obj[1: 3] = 6
是通过索引位置来更新obj
。
obj = pd.Series(['Shobhit', 'vaibhav', 'vimal', 'Sourabh'], index=['a', 'b', 'c', 'd'])
obj['b': 'c'] = 5
print(obj)
# a Shobhit
# b 5
# c 5
# d Sourabh
# dtype: object
obj[1: 3] = 6
print(obj)
# a Shobhit
# b 6
# c 6
# d Sourabh
# dtype: object
DataFrame的索引与切片。 data[['Three', 'Two']]
选取指定列,注意输入列条件是列表['Three', 'Two']
。
data = pd.DataFrame(
np.arange(16).reshape(4, 4),
index=['Ohio', 'Colorado', 'Utah', 'New York'],
columns=['One', 'Two', 'Three', 'Four']
)
print(data)
# One Two Three Four
# Ohio 0 1 2 3
# Colorado 4 5 6 7
# Utah 8 9 10 11
# New York 12 13 14 15
print(data['Two'])
# Ohio 1
# Colorado 5
# Utah 9
# New York 13
# Name: Two, dtype: int64
print(data[['Three', 'Two']])
# Three Two
# Ohio 2 1
# Colorado 6 5
# Utah 10 9
# New York 14 13
print(data[:2])
# One Two Three Four
# Ohio 0 1 2 3
# Colorado 4 5 6 7
嵌套:根据一个布尔值数组切片或选择数据。 data['Three'] > 5
是一个布尔值序列。 data[data['Three'] > 5]
输出条件为True的结果集。
print(data['Three'] > 5)
# Ohio False
# Colorado True
# Utah True
# New York True
# Name: Three, dtype: bool
print(data[data['Three'] > 5])
# One Two Three Four
# Colorado 4 5 6 7
# Utah 8 9 10 11
# New York 12 13 14 15
使用布尔值DataFrame进行索引,已经更新。 在下面这个例子中,这种索引方式使得DataFrame在语法上更像是NumPy二维数组。
print(data < 5)
# One Two Three Four
# Ohio True True True True
# Colorado True False False False
# Utah False False False False
# New York False False False False
data[data < 5] = 0
print(data)
# 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
使用loc和iloc选择数据。 使用标签名loc
或标签位置iloc
以NumPy风格的语法从DataFrame中选出Dataframe的行和列的子集。
data = pd.DataFrame(
np.arange(16).reshape(4, 4),
index=['Ohio', 'Colorado', 'Utah', 'New York'],
columns=['One', 'Two', 'Three', 'Four']
)
print(data)
# One Two Three Four
# Ohio 0 1 2 3
# Colorado 4 5 6 7
# Utah 8 9 10 11
# New York 12 13 14 15
下例通过loc对标签名筛选行或列数据。例如,输出Colorado
行标签的Two
和Three
这两列的值,以行记录的方式展现。
print(data.loc['Colorado', ['Two', 'Three']]) # 切片:
# Two 5
# Three 6
# Name: Colorado, dtype: int64
print(data.loc[:'Ohio', :'Two']) # 切片: 0行,0,1列
# One Two
# Ohio 0 1
下例通过标签位置iloc
进行类似的数据选择。 data.iloc[:3, :2][data > 4]
按指定条件进行行、列筛选,符合条件[data > 4]
的输出Dataframe值,不符合条件的输出NaN。
print(data.iloc[[0]]) # 0行
# One Two Three Four
# Ohio 0 1 2 3
print(data.iloc[[0], [1]]) # 切片: 0行,1列
# Two
# Ohio 1
print(data.iloc[1:2, 1:2]) # 切片: 1行,2列
# Two
# Ohio 1
print(data.iloc[2, [3, 0, 1]]) # 切片: 2行,依次取3,0,1列
# Four 11
# One 8
# Two 9
# Name: Utah, dtype: int64
print(data.iloc[:3, :2][data > 4])
# One Two
# Ohio NaN NaN
# Colorado NaN 5.0
# Utah 8.0 9.0
整数索引 ¶
Pandas的Series的索引值是整数索引。
data = np.arange(3.)
ser = pd.Series(data)
print(ser)
# 0 0.0
# 1 1.0
# 2 2.0
# dtype: float64
print(ser[:1])
# 0 0.0
# dtype: float64
print(ser.loc[:1]) # loc用于标签名
# 0 0.0
# 1 1.0
# dtype: float64
print(ser.iloc[:1]) # iloc用于标签位置
# 0 0.0
# dtype: float64
data = ['1', 'b', 'e', 3]
ser = pd.Series(data)
print(ser)
# 0 1
# 1 b
# 2 e
# 3 3
# dtype: object
print(ser[:1])
# 0 1
# dtype: object
print(ser.loc[:1])
# 0 1
# 1 b
# dtype: object
print(ser.iloc[:1])
# 0 1
# dtype: object
对DataFrame的更新。
df1 = pd.DataFrame(np.arange(4).reshape((2, 2)), columns=list('ab'))
print(df1)
# a b
# 0 0 1
# 1 2 3
# 按标签名更新
df1.loc[1, :'b'] = np.nan
print(df1)
# a b
# 0 0.0 1.0
# 1 NaN NaN
算术和数据对齐 ¶
Pandas支持在Series或者DataFrame对象之间进行算术运算。
例:两个Series做算术加法。
- 返回的结果也是一个Series。
- 返回结果的索引是每个Series的索引的并集。
- 凡是没有在两个Series都出现的索引位置,内部数据对齐会填充缺失值NaN。缺失值会在后续的其它算术操作上产生影响。
- 同时出现在两个Series的索引位置,Series的值做算术相加。
s1 = pd.Series(
[7.3, -2.5, 3.4, 1.5],
index=['a', 'c', 'd', 'e']
)
s2 = pd.Series(
[-2.1, 3.6, -1.5, 4, 3.1],
index=['a', 'c', 'e', 'f', 'g']
)
print(s1)
# a 7.3
# c -2.5
# d 3.4
# e 1.5
# dtype: float64
print(s2)
# a -2.1
# c 3.6
# e -1.5
# f 4.0
# g 3.1
# dtype: float64
print(s1 + s2)
# a 5.2
# c 1.1
# d NaN
# e 0.0
# f NaN
# g NaN
# dtype: float64
例:两个Dataframe做算术加法
- 返回结果也是一个Dataframe。
- 返回结果的行列索引是每个DataFrame的行列索引的并集。
- 凡是没有在两个DataFrame都出现的位置就会被置为NaN。
- 两个DataFrame都出现的位置,对Dataframe的值做算术加法。
df1 = pd.DataFrame(
np.arange(9).reshape((3, 3)),
columns=list('bcd'),
index=['Ohio', 'Texas', 'Colorado']
)
df2 = pd.DataFrame(
np.arange(12).reshape((4, 3)),
columns=list('bde'),
index=['Utah', 'Ohio', 'Texas', 'Oregon']
)
print(df1)
# b c d
# Ohio 0 1 2
# Texas 3 4 5
# Colorado 6 7 8
print(df2)
# b d e
# Utah 0 1 2
# Ohio 3 4 5
# Texas 6 7 8
# Oregon 9 10 11
print(df1 + df2)
# b c d e
# Colorado NaN NaN NaN NaN
# Ohio 3.0 NaN 6.0 NaN
# Oregon NaN NaN NaN NaN
# Texas 9.0 NaN 12.0 NaN
# Utah NaN NaN NaN NaN
在Series或者DataFrame对象之间进行算术操作时,有时需要对缺失值指定填充值,比如当轴标签在一个对象中存在,在另一个对象中不存在时,将缺失值填充为0。也就是说,如果在两个DataFrame都缺失,那么依然还会是NaN。
下例中a2是在df1
和df2
都缺失的位置,所以即使fill_value=0
,a2仍然是NaN。
df1 = pd.DataFrame(
np.arange(4).reshape((2, 2)),
columns=list('ab')
)
df2 = pd.DataFrame(
np.arange(9).reshape((3, 3)),
columns=list('bcd')
)
print(df1)
# a b
# 0 0 1
# 1 2 3
print(df2)
# b c d
# 0 0 1 2
# 1 3 4 5
# 2 6 7 8
# 对df1和df2就算术和,对应没有行列共同的交集的地方填充空值NaN,有交集的地方求算术和。
print(df1.add(df2))
# a b c d
# 0 NaN 1.0 NaN NaN
# 1 NaN 6.0 NaN NaN
# 2 NaN NaN NaN NaN
# 对df1和df2就算术和,对应没有行列共同的交集的地方填充空值0,有交集的地方求算术和。
print(df1.add(df2, fill_value=0)) # df2.add(df1, fill_value=0) 返回同样的结果
# a b c d
# 0 0.0 1.0 1.0 2.0
# 1 2.0 6.0 4.0 5.0
# 2 NaN 6.0 7.0 8.0
下例中b2是在df1
和df2
都缺失的位置,所以即使fill_value=0
,b2仍然是NaN。
df1 = pd.DataFrame(
np.arange(4).reshape((2, 2)),
columns=list('ab')
)
df2 = pd.DataFrame(
np.arange(9).reshape((3, 3)),
columns=list('acd')
)
print(df1)
# a b
# 0 0 1
# 1 2 3
print(df2)
# a c d
# 0 0 1 2
# 1 3 4 5
# 2 6 7 8
print(df1.add(df2, fill_value=0))
# a b c d
# 0 0.0 1.0 1.0 2.0
# 1 5.0 3.0 4.0 5.0
# 2 6.0 NaN 7.0 8.0
下例中没有两个DataFrame共同缺失的情况。
df1 = pd.DataFrame(
np.arange(4).reshape((2, 2)),
columns=list('ab')
)
df2 = pd.DataFrame(
np.arange(9).reshape((3, 3)),
columns=list('abd')
)
print(df1)
# a b
# 0 0 1
# 1 2 3
print(df2)
# a b d
# 0 0 1 2
# 1 3 4 5
# 2 6 7 8
print(df1.add(df2, fill_value=0))
# a b d
# 0 0.0 2.0 2.0
# 1 5.0 7.0 5.0
# 2 6.0 7.0 8.0
下面是Series和DataFrame的算术方法。
- add,radd:加法(+)
- sub,rsub:减法(-)
- div,rdiv:除法(/)
- floordiv,rfloordiv:整除(//)
- mul,rmul:乘法(*)
- pow,rpow:幂次方(**)
上述每个方法都有一个以r开头的副本,这些副本方法的参数是翻转的。比如,求DataFrame当中所有元素的倒数1/df
,可以写成df.rdiv(1)。
df1 = pd.DataFrame(
np.arange(4).reshape((2, 2)),
columns=list('ab')
)
df2 = pd.DataFrame(
np.arange(9).reshape((3, 3)),
columns=list('abd')
)
print(df1)
# a b
# 0 0 1
# 1 2 3
print(df2)
# a b d
# 0 0 1 2
# 1 3 4 5
# 2 6 7 8
print(df1.radd(df2, fill_value=0))
# a b d
# 0 0.0 2.0 2.0
# 1 5.0 7.0 5.0
# 2 6.0 7.0 8.0
print(df1.sub(df2, fill_value=0))
# a b d
# 0 0.0 0.0 -2.0
# 1 -1.0 -1.0 -5.0
# 2 -6.0 -7.0 -8.0
print(df1.div(df2, fill_value=0))
# a b d
# 0 NaN 1.00 0.0
# 1 0.666667 0.75 0.0
# 2 0.000000 0.00 0.0
print(df1.floordiv(df2, fill_value=0))
# a b d
# 0 NaN 1.0 0.0
# 1 0.0 0.0 0.0
# 2 0.0 0.0 0.0
print(df1.mul(df2, fill_value=0))
# a b d
# 0 0.0 1.0 0.0
# 1 6.0 12.0 0.0
# 2 0.0 0.0 0.0
print(df1.pow(df2, fill_value=0))
# a b d
# 0 1.0 1.0 0.0
# 1 8.0 81.0 0.0
# 2 0.0 0.0 0.0
DataFrame和Series间的算术操作 ¶
DataFrame和Series间的算术操作与NumPy中不同维度数组间的操作类似。
不同维度NumPy数组间的算术操作 ¶
从arr中减去arr[0]时,减法沿0轴在每一行都进行了操作。这就是所谓的广播机制。
arr = np.arange(12).reshape((3, 4))
print(arr)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
print(arr[0])
# [0 1 2 3]
print(arr - arr[0])
# [[0 0 0 0]
# [4 4 4 4]
# [8 8 8 8]]
DataFrame和Series间算术操作 ¶
默认情况下,DataFrame和Series的数学操作中会将Series的索引和DataFrame的*列*进行匹配,并*广播到各行*.
如果一个索引值不在DataFrame的列中,也不在Series的索引中,则新对象会构建并集索引。
frame = pd.DataFrame(
np.arange(12).reshape((4, 3)),
columns=list('bde'),
index=['Utah', 'Ohio', 'Texas', 'Oregon']
)
print(frame)
# b d e
# Utah 0 1 2
# Ohio 3 4 5
# Texas 6 7 8
# Oregon 9 10 11
# 截取frame的第0行,列标签变成新Serise的索引。
series = frame.iloc[0]
print(series)
# b 0
# d 1
# e 2
# Name: Utah, dtype: int64
series2 = pd.Series(
range(3),
index=list('bef')
)
print(series2)
# b 0
# e 1
# f 2
# dtype: int64
# 截取frame的d列,行标签变成新Serise的索引。
series3 = frame['d']
print(series3)
# Utah 1
# Ohio 4
# Texas 7
# Oregon 10
# Name: d, dtype: int64
# 将Series的索引和DataFrame的列标签进行匹配,Series的值沿DataFrame的0轴广播到各个行。
print(frame - series)
# frame: series Result:
# b d e # b 0 # b d e
# Utah 0 1 2 # d 1 # Utah 0 0 0
# Ohio 3 4 5 # e 2 # Ohio 3 3 3
# Texas 6 7 8 # Name: Utah, dtype: int64 # Texas 6 6 6
# Oregon 9 10 11 # Oregon 9 9 9
# 将Series的索引和DataFrame的列标签进行匹配,Series的值沿DataFrame的0轴广播到各个行,缺失位置填充空值NaN。
print(frame - series2)
# frame: series2 Result:
# b d e # b 0 # b d e f
# Utah 0 1 2 # e 1 # Utah 0.0 NaN 1.0 NaN
# Ohio 3 4 5 # f 2 # Ohio 3.0 NaN 4.0 NaN
# Texas 6 7 8 # dtype: int64 # Texas 6.0 NaN 7.0 NaN
# Oregon 9 10 11 # Oregon 9.0 NaN 10.0 NaN
# 改为在列上进行广播,在行上匹配,必须作用在某种算术方法上。下例中Series的值沿DataFrame的0轴广播到各个行(按index匹配进行行操作)。
print(frame.sub(series3, axis='index')) # 或axis=0
# frame: series3 Result:
# b d e # Utah 1 # b d e
# Utah 0 1 2 # Ohio 4 # Utah -1 0 1
# Ohio 3 4 5 # Texas 7 # Ohio -1 0 1
# Texas 6 7 8 # Oregon 10 # Texas -1 0 1
# Oregon 9 10 11 # Name: d, dtype: int64 # Oregon -1 0 1
函数应用和映射 ¶
NumPy的通用函数(逐元素数组方法)对pandas对象(DataFrame和Series)也有效。
frame = pd.DataFrame(
np.random.randn(4, 3),
columns=list('bde'),
index=['Utah', 'Ohio', 'Texas', 'Oregon']
)
print(frame)
# b d e
# Utah 2.737734 -0.379977 0.758933
# Ohio 0.847497 0.839583 -2.192021
# Texas -0.907544 -0.457436 -1.907396
# Oregon 0.389362 0.250170 1.065889
# 对DataFrame对象计算绝对值。
print(np.abs(frame))
# b d e
# Utah 2.737734 0.379977 0.758933
# Ohio 0.847497 0.839583 2.192021
# Texas 0.907544 0.457436 1.907396
# Oregon 0.389362 0.250170 1.065889
# f返回一个标量值
f = lambda x: x.max() - x.min()
# 沿0轴应用f(对每列的所有行元素进行f计算), 默认axis=0
print(frame.apply(f))
# b 3.645278
# d 1.297019
# e 3.257911
# dtype: float64
# 沿1轴应用f(对每行的所有列元素进行f计算)
print(frame.apply(f, axis=1))
# Utah 3.117711
# Ohio 3.039518
# Texas 1.449961
# Oregon 0.815720
# dtype: float64
# 定义函数f,返回带有多个值的Series。
def f(x):
return pd.Series(
[x.min(), x.max()],
index=['min', 'max']
)
print(frame.apply(f))
# b d e
# min -0.907544 -0.457436 -2.192021
# max 2.737734 0.839583 1.065889
# 定义函数f,使用applymap方法格式化字符,将一个逐元素的函数应用到Series上。
f = lambda x: '%.2f' % x
print(frame.applymap(f)) #
# b d e
# Utah 2.74 -0.38 0.76
# Ohio 0.85 0.84 -2.19
# Texas -0.91 -0.46 -1.91
# Oregon 0.39 0.25 1.07
print(frame['e'].map(f))
# Utah 0.76
# Ohio -2.19
# Texas -1.91
# Oregon 1.07
# Name: e, dtype: object
排序和排名 ¶
使用sort_index方法,按行或列索引进行字典型排序,返回一个新的排序好的Pandas对象。
Series排序 ¶
对Series进行索引排序和值排序。
obj = pd.Series(
range(4),
index=list('dabc')
)
print(obj)
# d 0
# a 1
# b 2
# c 3
# dtype: int64
print(obj.sort_index())
# a 1
# b 2
# c 3
# d 0
# dtype: int64
# print(obj.sort_values())
# d 0
# a 1
# b 2
# c 3
# dtype: int64
默认情况下,所有的缺失值都会被排序至Series的尾部。
obj = pd.Series([4, np.nan, 7, np.nan, -3, 2])
print(obj)
# 0 4.0
# 1 NaN
# 2 7.0
# 3 NaN
# 4 -3.0
# 5 2.0
# dtype: float64
print(obj.sort_values())
# 4 -3.0
# 5 2.0
# 0 4.0
# 2 7.0
# 1 NaN
# 3 NaN
# dtype: float64
DataFrame排序 ¶
frame = pd.DataFrame(
[[0, 1, 10, 3],
[4, 5, 6, 21],
[8, 9, 2, 21]],
index=['three', 'one', 'five'],
columns=list('dabc')
)
print(frame)
# d a b c
# three 0 1 10 3
# one 4 5 6 21
# five 8 9 2 21
print(frame.index)
# Index(['three', 'one', 'five'], dtype='object')
# 默认0轴,所有行进行索引首字母升序
print(frame.sort_index())
# d a b c
# five 8 9 2 21
# one 4 5 6 21
# three 0 1 10 3
# 指定0轴,所有行进行索引首字母升序
print(frame.sort_index(axis=0))
# d a b c
# five 8 9 2 21
# one 4 5 6 21
# three 0 1 10 3
# 指定0轴,所有行进行索引首字母降序
print(frame.sort_index(axis=0, ascending=False))
# d a b c
# three 0 1 10 3
# one 4 5 6 21
# five 8 9 2 21
# 指定1轴,所有列进列索引首字母升序
print(frame.sort_index(axis=1))
# a b c d
# three 1 10 3 0
# one 5 6 21 4
# five 9 2 21 8
# 指定1轴,所有列进列索引首字母降序
print(frame.sort_index(axis=1, ascending=False))
# d c b a
# three 0 3 10 1
# one 4 21 6 5
# five 8 21 2 9
# 按指定单列进行值排序(降序)
print(frame.sort_values(by=['c'], ascending=False))
# d a b c
# one 4 5 6 21
# five 8 9 2 21
# three 0 1 10 3
# 按指定多列进行值排序(降序),先对b降序,再对d降序
print(frame.sort_values(by=['c', 'd'], ascending=False))
# d a b c
# five 8 9 2 21
# one 4 5 6 21
# three 0 1 10 3
排名 ¶
**排名**是指对数组从1到有效数据点总数分配名次的操作。
- Series和DataFrame的
rank
方法是实现排名的方法, df.rank(ascending=False, method='max')
。ascending
:排名方式,默认从低到高,ascending=False
表示从高到低;method
:排名方式,包括:- average:默认,在相等分组中,为各个值分配平均排名,即相同值的和除以该值的个数,即为该值的名次。
- min:使用整个分组的最小排名,即,对应相同值,取在顺序排名中最小的那个排名作为所有该值的排名。
- max:使用整个分组的最大排名,即,对应相同值,取在顺序排名中最大的那个排名作为所有该值的排名。
- first:按值再原始数据中出现顺序分配排名,谁出现的位置靠前,谁的排名靠前。
- dense:类似min方法,但排名总是在组间增加1,而不是组中相同的元素数,即相同值的排名相同,其他依次加1即可。
- 默认情况下,rank是通过“为各组分配一个平均排名”的方式破坏平级关系
# 按照每个元素的大小顺序给出一个平均排名
obj = pd.Series([7, -5, 7, 4, 2, 0, 4])
print(obj)
# 0 7
# 1 -5
# 2 7
# 3 4
# 4 2
# 5 0
# 6 4
# dtype: int64
print(obj.rank())
# 0 6.5
# 1 1.0
# 2 6.5
# 3 4.5
# 4 3.0
# 5 2.0
# 6 4.5
# dtype: float64
# index value rank
# 2 -5 1
# 6 0 2
# 5 2 3
# 4 4 4.5
# 7 4 4.5
# 1 7 6.5
# 3 7 6.5
# 根据元素的观察顺序进行分配。元素0和2没有使用平均排名6.5,它们被设成了6和7,因为数据中标签0位于标签2的前面。
print(obj.rank(method='first'))
# 0 6.0
# 1 1.0
# 2 7.0
# 3 4.0
# 4 3.0
# 5 2.0
# 6 5.0
# dtype: float64
# 按照max进行升序和降序
print(obj.rank(ascending=False, method='max'))
print(obj.rank(ascending=True, method='max'))
# Original Series Max with inc Max with dec
# 0 7 # 0 2.0 (最小) # 0 7.0 (最大)
# 1 -5 # 1 7.0 (最大) # 1 1.0 (最小)
# 2 7 # 2 2.0 (最小) # 2 7.0 (最大)
# 3 4 # 3 4.0 # 3 5.0
# 4 2 # 4 5.0 # 4 3.0
# 5 0 # 5 6.0 # 5 2.0
# 6 4 # 6 4.0 # 6 5.0
# dtype: float64 # dtype: float64 # dtype: float64
frame = pd.DataFrame(
{'b': [4.3, 7, -3, 2],
'a': [0, 1, 0, 1],
'c': [-2, 5, 8, -2]}
)
print(frame)
# b a c
# 0 4.3 0 -2
# 1 7.0 1 5
# 2 -3.0 0 8
# 3 2.0 1 -2
# 沿1轴对DataFrame进行rank操作,即,每一行各元素进行rank。
print(frame.rank(axis='columns')) # axis=1
# b a c
# 0 3.0 2.0 1.0
# 1 3.0 1.0 2.0
# 2 1.0 2.0 3.0
# 3 3.0 2.0 1.0
含有重复标签的轴索引 ¶
尽管很多pandas函数(比如reindex)需要标签是唯一的,但这个并不是强制性的。 索引的is_unique属性可以检查标签是否唯一。
带有重复索引的情况下,一个索引标签会以序列方式返回多个条目。不重复的索引则会以标量值的形式返回单个条目,这可能会使代码更复杂。
obj = pd.Series(range(5), index=['a', 'b', 'a', 'c', 'b'])
print(obj)
# a 0
# b 1
# a 2
# c 3
# b 4
# dtype: int64
print(obj.is_unique)
# True
print(obj.index.is_unique)
# False
# 返回重复索引对应值的序列。
print(obj['a'])
# a 0
# a 2
# dtype: int64
df = pd.DataFrame(np.random.randn(4, 3), index=['a', 'a', 'b', 'b'])
print(df)
# 0 1 2
# a -0.726164 0.531540 -0.521611
# a -1.539807 -0.710880 -0.992789
# b -0.975970 -0.470725 0.121958
# b -0.301495 1.072322 -1.542296
print(df.index.is_unique)
# False
print(df.loc['b'])
# 0 1 2
# b -0.520008 0.052574 0.638529
# b -1.928705 -1.099534 -1.605296
描述性统计概述与计算 ¶
pandas包含了一些常用数学、统计学方法。其中大部分属于归约或汇总统计的类别,这些方法从DataFrame的行或列中抽取一个Series或一系列值(如总和或平均值)。
与NumPy数组中的类似方法相比,pandas内建了处理缺失值的功能。
- 归约方法: sum()
- 积累型方法: cumsun()
- 既不是归约型方法也不是积累型方法: describe()
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']
)
print(df)
# one two
# a 1.40 NaN
# b 7.10 -4.5
# c NaN NaN
# d 0.75 -1.3
# axis=0, 返回一个每列算术和的Series
print(df.sum())
# one 9.25
# two -5.80
# dtype: float64
# axis=1且skipna=True, 返回一个每行和的Series, 忽略NA值, 填0。
print(df.sum(axis=1))
# a 1.40
# b 2.60
# c 0.00
# d -0.55
# dtype: float64
# 不忽略NA值,填NaN。
print(df.sum(axis=1, skipna=False))
# a NaN
# b 2.60
# c NaN
# d -0.55
# dtype: float64
# 只有1级索引,所以level=0和原索引没有区别,NaN填充0。
print(df.groupby(level=0).sum())
# one two
# a 1.40 0.0
# b 7.10 -4.5
# c 0.00 0.0
# d 0.75 -1.3
# 列one的最大值是在索引b, 列two的最大值是在索引d
print(df.idxmax())
# one b
# two d
# dtype: object
print(df.idxmin())
# one d
# two b
# dtype: object
# cumsun的意思是第n次的和是n-1次的和与n的和,one列d行的和就是one列a、b、c、d值的总和。
print(df.cumsum())
# one two
# a 1.40 NaN
# b 8.50 -4.5
# c NaN NaN
# d 9.25 -5.8
通过describe产生统计信息,注意,数值型和非数值型的describe的信息是不同的。
# 一次性产生多个汇总统计
print(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
obj = pd.Series(['a', 'a', 'b', 'c'] * 4)
print(obj)
# 0 a
# 1 a
# 2 b
# 3 c
# 4 a
# 5 a
# 6 b
# 7 c
# 8 a
# 9 a
# 10 b
# 11 c
# 12 a
# 13 a
# 14 b
# 15 c
# dtype: object
# 针对非数值型数据,describe产生另一种汇总统计
print(obj.describe())
# count 16
# unique 3
# top a
# freq 8
# dtype: object
相关性和协方差 ¶
协方差与相关系数也是在时域分析时常见的两个概念,他们都是用来描述数据“像不像”的。
协方差的通俗理解:
- 两个变量在变化过程中是同方向变化还是反方向变化?相同或者相反程度如何?
- 你变大,同时我变大,说明两个变量是同向变化,这时协方差就是正的。
- 你变大,同时我变小,说明两个变量是反向变化,这时协方差就是负的。
- 从数值看,协方差的数值越大,两个变量同向程度也就越大。反之亦然。
相关系数的通俗理解:
- 用X,Y的协方差除以X的标准差和Y的标准差。相关系数也可以看成协方差,一种提出了两个变量量纲影响、标准化后的特殊协方差。所以:也可以反映两个变量变化时是同向还是反向,如果同向变化就为正,反向变化就为负。
- 由于是标准版后的协方差,相关系数消除了两个变量变化幅度的影响,而只是单纯反应两个变量每单位变化时的相似程度。
总结:
- 对于两个变量X、Y,
- 当他们的相关系数为1时,说明两个变量变化时的正向相似度最大。
- 当他们的相关系数为-1时,说明两个变量变化的反向相似度最大。
- 随着他们相关系数减小,两个变量变化时的相似度也变小,当相关系数为0时,两个变量的变化过程没有任何相似度,也即两个变量无关。
- 当相关系数继续变小,小于0时,两个变量开始出现反向的相似度,随着相关系数继续变小,反向相似度会逐渐变大。
下面的例子使用 pandas-datareader:
在所有例子中,在计算相关性之前,数据点已经按标签进行了对齐。
下例需要通过pandas-datareader库从Yahoo! Finance上获取的包含股价和交易量的DataFrame。
import pandas_datareader.data as web
all_data = {
ticker: web.get_data_yahoo(ticker) for ticker in ['AAPL', 'IBM', 'MSFT', 'GOOG']
}
price = pd.DataFrame(
{
ticker: data['Adj Close'] for ticker, data in all_data.items()
}
)
volume = pd.DataFrame(
{
ticker: data['Volume'] for ticker, data in all_data.items()
}
)
returns = price.pct_change()
print(returns.tail())
# AAPL IBM MSFT GOOG
# Date
# 2021-08-09 -0.000342 -0.008424 -0.003904 0.007049
# 2021-08-10 -0.003354 0.000920 -0.006555 0.000685
# 2021-08-11 0.001786 0.005305 0.001781 -0.002947
# 2021-08-12 0.020773 0.006614 0.009967 0.005084
# 2021-08-13 0.001410 0.000769 0.010490 0.000119
Series的corr方法计算的是两个Series中重叠的、非NA的、按索引对齐的值的相关性。相应地,cov计算的是协方差
print(returns['MSFT'])
# Date
# 2016-08-15 NaN
# 2016-08-16 -0.005540
# 2016-08-17 0.002089
# 2016-08-18 0.000695
# 2016-08-19 0.000347
# ...
# 2021-08-09 -0.003904
# 2021-08-10 -0.006555
# 2021-08-11 0.001781
# 2021-08-12 0.009967
# 2021-08-13 0.010490
# Name: MSFT, Length: 1259, dtype: float64
# Series的corr方法计算的是两个Series中重叠的、非NA的、按索引对齐的值的相关性。
print(returns['MSFT'].corr(returns['IBM']))
# 0.5175237180581937
# 等同写法,MSFT是一个有效的Python属性
print(returns.MSFT.corr(returns.IBM))
# 0.5175237180581937
# Series的cov方法计算的是两个Series中值的协方差。
print(returns['MSFT'].cov(returns['IBM']))
# 0.0001452224236764915
DataFrame的corr和cov方法会分别以DataFrame的形式返回相关性和协方差矩阵。
print(returns.corr())
# AAPL IBM MSFT GOOG
# AAPL 1.000000 0.441111 0.735539 0.661961
# IBM 0.441111 1.000000 0.517524 0.484230
# MSFT 0.735539 0.517524 1.000000 0.775756
# GOOG 0.661961 0.484230 0.775756 1.000000
# 给corrwith方法,传入一个Series时,会返回一个含有为每列计算相关性值的Series
print(returns.corrwith(returns['IBM']))
# AAPL 0.441111
# IBM 1.000000
# MSFT 0.517524
# GOOG 0.484230
# dtype: float64
# 给corrwith方法,传入一个DataFrame时,会计算匹配到列名的相关性数值。下面是计算交易量百分比变化的相关性
print(returns.corrwith(volume))
# AAPL -0.063111
# IBM -0.103721
# MSFT -0.056842
# GOOG -0.119026
# dtype: float64
print(returns.cov())
# AAPL IBM MSFT GOOG
# AAPL 0.000361 0.000137 0.000240 0.000211
# IBM 0.000137 0.000268 0.000145 0.000133
# MSFT 0.000240 0.000145 0.000294 0.000224
# GOOG 0.000211 0.000133 0.000224 0.000282
唯一值、计数和成员属性 ¶
obj = pd.Series(['c', 'a', 'd', 'a', 'a', 'a', 'b', 'b', 'c', 'c'])
print(obj)
# 0 c
# 1 a
# 2 d
# 3 a
# 4 a
# 5 a
# 6 b
# 7 b
# 8 c
# 9 c
# dtype: object
函数unique
给出Series中的唯一值。
print(obj.unique())
# ['c' 'a' 'd' 'b']
print(obj.sort_values().unique())
# ['a' 'b' 'c' 'd']
# value_counts计算Series包含的值的个数
print(obj.value_counts())
# a 4
# c 3
# b 2
# d 1
# dtype: int64
# 这里value_counts不是Series的方法,是pandas顶层方法
print(pd.value_counts(obj.values, sort=True))
# a 4
# c 3
# b 2
# d 1
# dtype: int64
print(obj.isin(['b', 'c']))
# 0 True
# 1 False
# 2 False
# 3 False
# 4 False
# 5 False
# 6 True
# 7 True
# 8 True
# 9 True
# dtype: bool
# 将上面的结果作为列表输入的条件,输出为True的结果
print(obj[obj.isin(['b', 'c'])])
# 0 c
# 6 b
# 7 b
# 8 c
# 9 c
# dtype: object
obj1 = pd.Series(['c', 'a', 'd', 'a', 'a', 'a', 'b', 'b', 'c', 'c'])
obj2 = pd.Series(['c', 'a', 'b'])
print(pd.Index(obj1))
# Index(['c', 'a', 'd', 'a', 'a', 'a', 'b', 'b', 'c', 'c'], dtype='object')
print(pd.Index(obj2))
# Index(['c', 'a', 'b'], dtype='object')
# 这里0对应obj2里面的c在job1的位置,以此类推,生成新的索引列表
print(pd.Index(obj2).get_indexer(obj1))
# [ 0 1 -1 1 1 1 2 2 0 0]
计算DataFrame多个相关列的直方图。
data = pd.DataFrame(
{
'Que1': [1, 3, 4, 3, 4],
'Que2': [2, 3, 1, 2, 3],
'Que3': [1, 5, 2, 4, 4],
}
)
print(data)
# Que1 Que2 Que3
# 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).fillna(0)
# 下面结果中的行标签是所有列中出现的不同值,数值则是这些不同值在每个列中出现的次数,例如:数字5只在Que3里面出现了一次
print(result)
# Que1 Que2 Que3
# 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