[ Pandas version: 1.0.1 ]
import pandas as pd
一、Pandas对象
Pandas的三个基本数据结构:Series, DataFrame, Index
(一) Pandas的Series对象
Pandas的Series对象是一个带索引数据构成的一维数组。
通过values
属性和index
属性获取数据。values属性返回的结果与NumPy数组类似。
data = pd.Series([0.25, 0.5, 0.75, 1.0])
#0 0.25
#1 0.50
#2 0.75
#3 1.00
#dtype: float64
data.values #输出:array([0.25, 0.5 , 0.75, 1. ])
data.index #输出:RangeIndex(start=0, stop=4, step=1)
data[1]
data[1:3]
#1 0.50
#2 0.75
#dtype: float64
- Series是通用的NumPy数组
NumPy数组通过隐式定义的整数索引获取数值。
Pandas的Series对象通过显式定义的索引与数值关联,其索引可以是任意类型,可使用不连续或不按顺序的索引。
data = pd.Series([0.25, 0.5, 0.75, 1.0], index=['a', 'b', 'c', 'd'])
data = pd.Series([0.25, 0.5, 0.75, 1.0], index=[2, 5, 3, 7])
- Series是特殊的字典
Python字典是一种将任意键映射到一组任意值的数据结构。
Series对象是一直将类型键映射到一组类型值的数据结构,支持字典不具有的功能,如切片。
population_dict = {'California': 38332521, 'Texas': 26448193, 'New York': 19651127}
population = pd.Series(population_dict)
# California 38332521
# Texas 26448193
# New York 19651127
# dtype: int64
population['California']
# 切片
population['California':'Texas']
- 创建Series对象:
pd.Series(data, index=index)
- 其中
index
是可选参数,data
参数支持多种数据类型。 - Series对象只会保留显式定义的键值对。
- 每种形式都可以通过显示指定索引筛选需要的结果
# 1. data是列表或NumPy数组,这时index默认值为整数序列
pd.Series([2, 4, 6])
# 2. data是标量,创建Series对象时会重复填充到每个索引上
pd.Series(5, index=[100, 200, 300])
# 3. data是字典,index默认是排序的字典键
pd.Series({2:'a', 1:'b', 3:'c'})
# 每种形式都可以通过显示指定索引筛选需要的结果
pd.Series({2:'a', 1:'b', 3:'c'}, index=[3, 2])
#3 c
#2 a
#dtype: object
(二) Pandas的DataFrame对象
- DataFrame是通用的NumPy数组
DataFrame可以看做是一种有行和列索引的二维数组,也可看作是有序排列(有共同索引)的若干Series对象。
area_dict = {'California': 423967, 'Texas': 695662, 'New York': 141297}
area = pd.Series(area_dict)
states = pd.DataFrame({'population': population, 'area': area})
states
# population area
# California 38332521 423967
# Texas 26448193 695662
# New York 19651127 141297
DataFrame属性:index
、columns
# DataFrame有index属性获取索引标签
states.index #输出:Index(['California', 'Texas', 'New York'], dtype='object')
# DataFrame有columns属性存放列标签的index对象
states.columns #输出:Index(['population', 'area'], dtype='object')
- DataFrame是特殊的字典:一列映射一个Series的数据
states['area']
# California 423967
# Texas 695662
# New York 141297
# Name: area, dtype: int64
- 创建DataFrame对象:
pd.DataFrame(data, columns=columns, index=index)
# 1. 通过单个Series对象创建
pd.DataFrame(population, columns=['population'])
# population
# California 38332521
# Texas 26448193
# New York 19651127
# 2. 通过字典列表创建
data = [{'a': i, 'b': 2 * i} for i in range(3)] #data: [{'a': 0, 'b': 0}, {'a': 1, 'b': 2}, {'a': 2, 'b': 4}]
pd.DataFrame(data)
# a b
# 0 0 0
# 1 1 2
# 2 2 4
# 即使字典中有些键不存在,Pandas也会用缺失值NaN表示
pd.DataFrame([{'a': 1, 'b': 2}, {'b': 3, 'c': 4}])
# a b c
# 0 1.0 2 NaN
# 1 NaN 3 4.0
# 3. 通过Series对象字典创建
pd.DataFrame({'population': population, 'area': area})
# 4. 通过NumPy二维数组创建
pd.DataFrame(np.random.rand(3, 2), columns=['foo', 'bar'], index=['a', 'b', 'c'])
# foo bar
# a 0.428555 0.416076
# b 0.368652 0.115681
# c 0.381276 0.704019
# 注:如果不指定行列索引值,那么行列默认都是整数索引值
pd.DataFrame(np.random.rand(3, 2)
# 0 1
# 0 0.973628 0.960743
# 1 0.312451 0.824474
# 2 0.956125 0.275362
# 5. 通过NumPy结构化数组创建
A = np.zeros(3, dtype=[('A', 'i8'), ('B', 'f8')])
A #输出:array([(0, 0.), (0, 0.), (0, 0.)], dtype=[('A', '<i8'), ('B', '<f8')])
pd.DataFrame(A)
# A B
# 0 0 0.0
# 1 0 0.0
# 2 0 0.0
(三) Pandas的Index对象
- 将Index看作不可变数组
Index对象的索引是不可变的,这个不可变特性使得多个DataFrame和数组之间进行索引共享时更加安全,尤其是可以避免因修改索引时粗心导致的副作用。
ind = pd.Index([2, 3, 5, 7, 11])
ind #输出:Int64Index([2, 3, 5, 7, 11], dtype='int64')
ind[1] #输出:3
ind[::2] #输出:Int64Index([2, 5, 11], dtype='int64')
print(ind.size, ind.shape, ind.ndim, ind.dtype)
# 5 (5,) 1 int64
#ind[1] = 0 -> TypeError 不可赋值
- 将Index看作有序集合(实际上是一个多集:Index对象可以包含重复值)
Pandas对象涉及许多集合操作,遵循Python集合的许多习惯用法,包括并集、交集、差集等。
indA = pd.Index([1, 3, 5, 7, 9])
indB = pd.Index([2, 3, 5, 7, 11])
indA & indB #交集,输出:Int64Index([3, 5, 7], dtype='int64')
indA | indB #并集,输出:Int64Index([1, 2, 3, 5, 7, 9, 11], dtype='int64')
indA ^ indB #异或,输出:Int64Index([1, 2, 9, 11], dtype='int64')
二、数据取值与选择
(一) Series数据选择方法
1. 将Series看作字典
data = pd.Series([0.25, 0.5, 0.75, 1.0], index=['a', 'b', 'c', 'd'])
data['b']
# 使用Python字典的表达式和方法检测索引和值
'a' in data #输出:True
data.keys() #输出:Index(['a', 'b', 'c', 'd'], dtype='object')
list(data.items()) #输出:[('a', 0.25), ('b', 0.5), ('c', 0.75), ('d', 1.0)]
# 增加新索引值扩展Series
data['e'] = 1.25
2. 将Series看作一维数组
# 数组数据选择功能:索引、花哨索引等
# 将显式索引作为切片
data['a': 'c']
# 将隐式索引作为切片
data[0:2]
# 掩码
data[(data > 3) & (data < 0.8)]
# 花哨索引
data[['a', 'e']]
- 当使用显式索引作切片时,结果包含最后一个索引;而当使用隐式索引作切片时,结果不包含最后一个索引。
3. 索引器:loc, iloc, ix
- 如果Series是显式整数索引,那么取值操作会使用显式索引,切片操作会使用隐式索引。(容易混淆)
data = pd.Series(['a', 'b', 'c'], index=[1, 3, 5])
# 1 a
# 3 b
# 5 c
# dtype: object
# 取值操作是显式索引
data[1] #输出:'a'
# 切片操作是隐式索引
data[1:3]
# 3 b
# 5 c
# dtype: object
第一种索引器:loc
属性,表示取值和切片都是显式的
data.loc[1] #输出:'a'
data.loc[1:3]
# 1 a
# 3 b
# dtype: object
第二种索引器:iloc
属性,表示取值和切片都是隐式索引(左闭右开区间)
data.iloc[1] #输出:'b'
data.iloc[1:3]
# 3 b
# 5 c
# dtype: object
第三种索引器:ix
,它是loc
和iloc
的混合形式,在Series对象中ix
等价于标准Python列表取值方式。ix
索引器主要用于DataFrame对象。
Python代码的设计原则之一是“显式优于隐式”,使用loc
和iloc
可以让代码更易维护,可读性更高(尤其是在处理整数索引的对象时)
(二) DataFrame数据选择方法
1. 将DataFrame看作字典(若干Series对象构成)
states
# pop area
# California 38332521 423967
# Texas 26448193 695662
# New York 19651127 141297
# 1. 通过对列名进行字典形式取值获取数据(dictionary-style)
states['area']
# 2. 用属性形式选择纯字符串列名的数据(attribute-style)
states.area
# 对同一个对象进行属性形式与字典形式的列数据结果相同
states.area is states['area'] #输出:True
# 如果列名不是纯字符串,或者列名与DataFrame的方法同名,就不能用属性索引
states.pop is states['pop'] #data.pop中,pop会显示为方法,无法获取列,输出:False
# 应该避免对用属性形式选择的列直接赋值
states['pop'] = z # ok
# states.pop = z # NO
# 可以用字典形式的语法调整对象:如,增加一列
states['density'] = states['pop'] / states['area']
# pop area density
# California 38332521 423967 90.413926
# Texas 26448193 695662 38.018740
# New York 19651127 141297 139.076746
2. 将DataFrame看作二维数组
# values属性按行查看数组数据
states.values
# array([[3.83325210e+07, 4.23967000e+05, 9.04139261e+01],
# [2.64481930e+07, 6.95662000e+05, 3.80187404e+01],
# [1.96511270e+07, 1.41297000e+05, 1.39076746e+02]])
# 行列转置
states.T
# 单个行索引获取一行数据
states.values[0] #输出:array([3.83325210e+07, 4.23967000e+05, 9.04139261e+01])
# 获取列数据
states['area']
# 索引器
states.iloc[:2, :1]
states.loc[:'Texas', :'area']
states.ix[:2, :'pop'] #注意:ix索引器对于整数索引的处理容易混淆
# 索引器结合掩码与花哨索引
states.loc[states.density > 100, ['pop', 'density']]
# pop density
#New York 19651127 139.076746
# 任意取值方法都可以用于调整数据
states.iloc[0, 2] = 90
3. 其他取值方法
# 如果对单个标签取值就选择列,而对多个标签用切片就选择行
states['California':'Texas']
# 切片也可以不用索引值,直接用行数实现
states[:1]
# 掩码操作也可以直接对每一行进行过滤,而不需要使用loc索引器
states[states.density > 100]
三、Pandas数值运算方法
Pandas集成了NumPy的功能,除此之外,Pandas在保存数据内容与组合不同来源的数据具有优势。
高效技巧:对于一元运算(如函数与三角函数)的通用函数将在输出结果中保留索引和列标签;对于二元运算(如加法和乘法),在传递通用函数时会自动对齐索引进行计算。
(一) 通用函数:保留索引
rng = np.random.RandomState(42)
ser = pd.Series(rng.randint(0, 10, 4))
ser
# 0 6
# 1 3
# 2 7
# 3 4
# dtype: int64
# Pandas对象使用NumPy通用函数,结果依然保留索引
np.exp2(ser)
# 0 64.0
# 1 8.0
# 2 128.0
# 3 16.0
# dtype: float64
(二) 通用函数:索引对齐
当在两个Series或DataFrame对象上进行二元运算时,Pandas会在计算过程中对齐两个对象的索引,这在处理不完整的数据时非常方便。
- Series索引对齐
- 整合两个数据源的数据,运算结果数组的索引时两个输入数组索引的并集。
- 对于缺失位置的数据,Pandas会默认用NaN填充,表示此处无数。
- 可以通过运算符方法的
fill_value
参数自定义缺失值
area = pd.Series({'Alaska': 1723337, 'Texas': 695662, 'California': 423967}, name='area')
population = pd.Series({'California': 38332521, 'Texas': 26448193, 'New York': 19651127}, name='population')
population / area
# Alaska NaN
# California 90.413926
# New York NaN
# Texas 38.018740
# dtype: float64
area.index | population.index
# Index(['Alaska', 'California', 'New York', 'Texas'], dtype='object')
A = pd.Series([2, 4, 6], index=[0, 1, 2])
B = pd.Series([1, 3, 5], index=[1, 2, 3])
A + B
# 0 NaN
# 1 5.0
# 2 9.0
# 3 NaN
# dtype: float64
# 如需避免NaN值,就用对象方法代替运算符,设置参数自定义缺失的数据
A.add(B, fill_value=0)
# 0 2.0
# 1 5.0
# 2 9.0
# 3 5.0
# dtype: float64
- DataFrame索引对齐
rng = np.random.RandomState(42)
A = pd.DataFrame(rng.randint(0, 20, (2, 2)), columns=list('AB'))
# A B
# 0 6 19
# 1 14 10
B = pd.DataFrame(rng.randint(0, 10, (3, 3)), columns=list('BAC'))
# B A C
# 0 7 4 6
# 1 9 2 6
# 2 7 4 3
# 两个对象的行列索引可以是不同顺序的,结果的索引会自动按顺序排列
A + B
# A B C
# 0 10.0 26.0 NaN
# 1 16.0 19.0 NaN
# 2 NaN NaN NaN
# 计算均值要用stack将二维数组压缩成一维数组
fill = A.stack().mean()
A.add(B, fill_value=fill)
# A B C
# 0 10.00 26.00 18.25
# 1 16.00 19.00 18.25
# 2 16.25 19.25 15.25
Python运算符与Pandas方法的映射关系
Pandas运算符 Pandas方法
+ add()
- sub(), subtract()
* mul(), multiply()
/ truediv(), div(), divide()
// floordiv()
% mod()
** pow()
(三) 通用函数:DataFrame与Series的运算
# 根据NumPy广播规则,让二维数组减自身的一行数据会按行计算。Pandas等同。
A = rng.randint(10, size=(3, 4))
A - A[0]
df = pd.DataFrame(A, columns=list('QRST'))
df - df.iloc[0]
# 按列计算,要用运算符方法,通过axis参数设置
df.subtract(df['R'], axis=0)
halfrow = df.iloc[0, ::2]
df - halfrow
Pandas相关阅读:
[Python3] Pandas v1.0 —— (一) 对象、数据取值与运算 【本文】
[Python3] Pandas v1.0 —— (二) 处理缺失值
[Python3] Pandas v1.0 —— (三) 层级索引
[Python3] Pandas v1.0 —— (四) 合并数据集
[Python3] Pandas v1.0 —— (五) 累计与分组
[Python3] Pandas v1.0 —— (六) 数据透视表
[Python3] Pandas v1.0 —— (七) 向量化字符串操作
[Python3] Pandas v1.0 —— (八) 处理时间序列
[Python3] Pandas v1.0 —— (九) 高性能Pandas: eval()与query()
总结自《Python数据科学手册》