看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
pandas 数据的索引就像一本书的目录,让我们很快地找到想要看的章节,作为大量数据,创建合理的具有业务意义的索引对我们分析数据至关重要。
下图是一个简单的 DataFrame 中索引的示例:
其中:
有时一个行和列层级较多的数据会出现多层索引 的情况。
之前我们学习了加载数据生成 DataFrame 时可以指定索引
data = 'https://gairuo.com/file/data/dataset/team.xlsx'
df = pd.read_excel(data, index_col='name') # 设置索引为 name
df
'''
team Q1 Q2 Q3 Q4
name
Liver E 89 21 24 64
Arry C 36 37 37 57
Ack A 57 60 18 84
Eorge C 93 96 71 78
Oah D 65 49 61 86
'''
如果加载时没有指定索引,我们可以使用 df.set_index()
指定:
df.set_index('month') # 设置月份为索引
df.set_index(['month', 'year']) # 设置月份和年为多层索引
'''
sale
month year
1 2012 55
4 2014 40
2013 84
10 2014 31
'''
s = pd.Series([1, 2, 3, 4])
df.set_index(s) # 指定一个索引
df.set_index([s, 'year']) # 指定的索引和现有字段同时指定
df.set_index([s, s**2]) # 计算索引
# 其他的参数
df.set_index('month', drop=False) # 保留原列
df.set_index('month', append=True) # 保留原来的索引
df.set_index('month', inplace=True) # 建立索引并重写覆盖 df
为了适应各种业务数据的处理,索引又针对各种类型数据定义了不同的索引类型:
共有以下几种:
pd.Index([1, 2, 3])
# Int64Index([1, 2, 3], dtype='int64')
pd.RangeIndex(1,100,2)
# RangeIndex(start=1, stop=100, step=2)
pd.Int64Index([1,2,3,-4], name='num') # v2.0 将弃用
# Int64Index([1, 2, 3, -4], dtype='int64', name='num')
pd.UInt64Index([1,2,3,4]) # v2.0 将弃用
# UInt64Index([1, 2, 3, 4], dtype='uint64')
pd.Float64Index([1.2,2.3,3,4]) # v2.0 将弃用
# Float64Index([1.2, 2.3, 3.0, 4.0], dtype='float64')
类别只能包含有限数量的(通常是固定的)可能值(类别)。 可以理解成枚举,比如性别只有男女,但在数据中每行都有,如果按文本处理会效率不高。类别的底层是 pandas.Categorical。
pd.CategoricalIndex(['a', 'b', 'a', 'b'])
# CategoricalIndex(['a', 'b', 'a', 'b'], categories=['a', 'b'], ordered=False, dtype='category')
类别后边后有专门的讲解,只有在体量非常大的数据面前才能显示其优势。
pd.interval_range(start=0, end=5)
'''
IntervalIndex([(0, 1], (1, 2], (2, 3], (3, 4], (4, 5]],
closed='right',
dtype='interval[int64]')
'''
教程后边会有专门的讲解。
arrays = [[1, 1, 2, 2], ['red', 'blue', 'red', 'blue']]
pd.MultiIndex.from_arrays(arrays, names=('number', 'color'))
'''
MultiIndex([(1, 'red'),
(1, 'blue'),
(2, 'red'),
(2, 'blue')],
names=['number', 'color'])
'''
# 从一个日期连续到另一个日期
pd.date_range(start='1/1/2018', end='1/08/2018')
# 指定开始时间和周期
pd.date_range(start='1/1/2018', periods=8)
# 以月为周期
pd.period_range(start='2017-01-01', end='2018-01-01', freq='M')
# 周期嵌套
pd.period_range(start=pd.Period('2017Q1', freq='Q'),
end=pd.Period('2017Q2', freq='Q'), freq='M')
pd.TimedeltaIndex(data =['06:05:01.000030', '+23:59:59.999999',
'22 day 2 min 3us 10ns', '+23:29:59.999999',
'+12:19:59.999999'])
# 使用 datetime
pd.TimedeltaIndex(['1 days', '1 days, 00:00:05',
np.timedelta64(2, 'D'),
datetime.timedelta(days=2, seconds=2)])
t = pd.period_range('2020-5-1 10:00:05', periods=8, freq='S')
pd.PeriodIndex(t,freq='S')
行和列的索引在 Pandas 里其实是一个 Index
对象,以下是创建一个 index
对象的方法:
pd.Index([1, 2, 3])
# Int64Index([1, 2, 3], dtype='int64')
pd.Index(list('abc'))
# Index(['a', 'b', 'c'], dtype='object')
# 可以定义一相 name
pd.Index(['e', 'd', 'a', 'b'], name='something')
df.index
# RangeIndex(start=0, stop=4, step=1)
df.columns
# Index(['month', 'year', 'sale'], dtype='object')
以下方法也适用于 df.columns
, 因为都是 index 对象:
# 属性
df.index.name # 名称
df.index.array # array 数组
df.index.dtype # 数据类型
df.index.shape # 形状
df.index.size # 元素数量
df.index.values # array 数组
# 其他,不常用
df.index.empty # 是否为空
df.index.is_unique # 是否不重复
df.index.names # 名称列表
df.index.is_all_dates # 是否全是日期时间
df.index.has_duplicates # 是否有重复值
df.index.values # 索引的值 array
以下方法也适用于 df.columns
, 因为都是 index 对象,有些也支持 Series:
# 方法
df.index.astype('int64') # 转换类型
df.index.isin() # 是否存在,见下方示例
df.index.rename('number') # 修改索引名称
df.index.nunique() # 不重复值的数量
df.index.sort_values(ascending=False,) # 排序,倒序
df.index.map(lambda x:x+'_') # map 函数处理
df.index.str.replace('_', '') # str 替换
df.index.str.split('_') # 分隔
df.index.to_list() # 转为列表
df.index.to_frame(index=False, name='a') # 转成 DataFrame
df.index.to_series() # 转 series
df.index.to_numpy() # 转为 numpy
df.index.unique() # 去重
df.index.value_counts() # 去重及数量
df.index.where(df.index=='a') # 筛选
df.index.rename('grade', inplace=False) # 重命名索引名称
df.index.rename(['species', 'year']) # 多层,重命名索引名称
df.index.max() # 最大值
df.index.argmax() # 最大索引值
df.index.any()
df.index.all()
df.index.T # 转置,多层索引里很有用
# 其他,不常用
df.index.append(pd.Index([4,5])) # 追加
df.index.repeat(2) # 重复几次
df.index.inferred_type # 推测数据类型
df.index.hasnans # 有没有空值
df.index.is_monotonic_decreasing # 是否单调递减
df.index.is_monotonic # 是否单调递增
df.index.is_monotonic_increasing # 是否单调递增
df.index.nbytes # 基础数据中的字节数
df.index.ndim # 维度数,维数
df.index.nlevels # 索引层级数,通常为 1
df.index.min() # 最小值
df.index.argmin() # 最小索引值
df.index.argsort() # 顺序值组成的数组
df.index.asof(2) # 返回最近的索引
# numpy dtype or pandas type
df.index.astype('int64', copy=True) # 深拷贝
# 拷贝
df.index.copy(name='new', deep=True, dtype='int64')
df.index.delete(1) # 删除指定位置
# 对比不同
df.index.difference(pd.Index([1,2,4]), sort=False)
df.index.drop('a', errors='ignore') # 删除
df.index.drop_duplicates(keep='first') # 去重值
df.index.droplevel(0) # 删除层级
df.index.dropna(how='all') # 删除空值
df.index.duplicated(keep='first') # 重复值在结果数组中为True
df.index.equals(df.index) # 与另外一个索引对象是否相同
df.index.factorize() # 分解成(array:0-n, Index)
df.index.fillna(0, {0:'nan'}) # 填充空值
# 字符列表, 把 name 值加在第一位, 每个值加10
df.index.format(name=True, formatter=lambda x:x+10)
# 返回一个 array, 指定值的索引位数组,不在的为 -1
df.index.get_indexer([2,9])
# 获取 指定层级 Index 对象
df.index.get_level_values(0)
# 指定索引的位置,见示例
df.index.get_loc('b')
df.index.insert(2, 'f') # 在索引位 2 插入 f
df.index.intersection(df.index) # 交集
df.index.is_(df.index) # 类似 is 检查
df.index.is_categorical() # 是否分类数据
df.index.is_type_compatible(df.index) # 类型是否兼容
df.index.is_type_compatible(1) # 类型是否兼容
df.index.isna() # array 是否为空
df.index.isnull() # array 是否缺失值
df.index.join(df.index, how='left') # 连接
df.index.notna() # 是否不存在的值
df.index.notnull() # 是否不存在的值
df.index.ravel() # 展平值的ndarray
df.index.reindex(['a','b']) # 新索引 (Index,array:0-n)
df.index.searchsorted('f') # 如果插入这个值排序后在哪个索引位
df.index.searchsorted([0, 4]) # array([0, 3]) 多个
df.index.set_names('quarter') # 设置索引名称
df.index.set_names('species', level=0)
df.index.set_names(['kind', 'year'], inplace=True)
df.index.shift(10, freq='D') # 日期索引向前移动 10 天
idx1.symmetric_difference(idx2) # 两个索引不同的内容
idx1.union(idx2) # 拼接
df.add_prefix('t_') # 表头加前缀
df.add_suffix('_d') # 表头加后缀
df.first_valid_index() # 第一个有值的索引
df.last_valid_index() # 最后一个有值的索引
# 掩码设置的值的新索引, 小于 10 的变为 0
df.index.putmask(df.index<10, 0)
有时我们想取消已有的索引,以重新来过,可以使用 df.reset_index()
:
df.reset_index() # 清除索引
df.set_index('month').reset_index() # 相当于啥也没干
# 删除原索引,month 列没了
df.set_index('month').reset_index(drop=True)
df2.reset_index(inplace=True) # 覆盖使生效
# year 一级索引取消
df.set_index(['month', 'year']).reset_index(level=1)
df2.reset_index(level='class') # 同上使用层级索引名
df.reset_index(level='class', col_level=1) # 列索引
# 不存在层级名称的填入指定名称
df.reset_index(level='class', col_level=1, col_fill='species')
如果想修改索引内容可以用df.reindex(['a','b'])
,还能用它做指定排序。
对行和列的索引名进行修改。
# 一一对应修改列索引
df.rename(columns={"A": "a", "B": "c"})
df.rename(str.lower, axis='columns')
# 修改行索引
df.rename(index={0: "x", 1: "y", 2: "z"})
df.rename({1: 2, 2: 4}, axis='index')
# 修改数据类型
df.rename(index=str)
# 重新修改索引
replacements = {l1:l2 for l1, l2 in zip(list1, list2)}
df.rename(replacements)
# 列名加前缀
df.rename(lambda x:'t_' + x, axis=1)
# 利用 iter() 函数的 next 特性修改
df.rename(lambda x, y=iter('abcdef'): next(y), axis=1)
# 修改列名,用解包形式生成新旧字段字典
df.rename(columns=dict(zip(df, list('abcd'))))
df.set_axis
可以将所需的索引分配给给定的轴。可以通过分配类似列表或索引的方式来更改列标签或行标签的索引。
# 修改索引
df.set_axis(['a', 'b', 'c'], axis='index')
# 修改列名
df.set_axis(list('abcd'), axis=1)
# 使修改生效
df.set_axis(['a', 'b'], axis='columns', inplace=True)
# 传入索引内容
df.set_axis(pd.Index(list('abcde')), axis=0)
注意,这是修改索引的名称,不是索引或者列名本身:
s.rename_axis("animal") # 索引重命名
df.rename_axis(["dow", "hr"]) # 多层索引索引名修改
df.rename_axis('info', axis="columns") # 修改行索引名
# 修改多层行索引名
df.rename_axis(index={'a': 'A', 'b': 'B'})
# 修改多层列索引名
df.rename_axis(columns={'name': 's_name', 'b': 'B'})
df.rename_axis(columns=str.upper) # 行索引名变大写
# idx.isin() 是否存在
idx = pd.Index([1,2,3])
df.index.isin(idx)
# array([False, False, False, False])
df.index.isin(['a','b'])
# array([ True, True, False, False])
midx = pd.MultiIndex.from_arrays([[1,2,3],
['red', 'blue', 'green']],
names=('number', 'color'))
midx.isin([(1, 'red'), (3, 'red')])
# array([ True, False, False])
dates = ['2000-03-11', '2000-03-12', '2000-03-13']
dti = pd.to_datetime(dates)
dti.isin(['2000-03-11'])
# array([ True, False, False])
# i.argsort() 排序
# 将对索引进行排序的整数索引,见下文示例
idx = pd.Index(['b', 'a', 'd', 'c'])
order = idx.argsort() # array([1, 0, 3, 2])
idx[order] # Index(['a', 'b', 'c', 'd'], dtype='object')
# i.asof(2) 返回最近的索引, 支持日期,可实现找最近日期
# 从索引中返回标签;如果不存在,则返回前一个标签
idx2 = pd.Index([1,3,6])
idx2.asof(5) # 3
idx2.asof(6) # 5
idx2.asof(-1) # nan
# index.get_loc 指定索引的位置,见示例
unique_index = pd.Index(list('abc'))
unique_index.get_loc('b') # 1
monotonic_index = pd.Index(list('abbc'))
monotonic_index.get_loc('b') # slice(1, 3, None)
non_monotonic_index = pd.Index(list('abcb'))
non_monotonic_index.get_loc('b')
# array([False, True, False, True], dtype=bool)
更多的操作可以看官方文档。
注:Pandas 版本要求 1.2.0+,这是一项实验功能
Pandas 默认地行列索引对象不需要唯一,可以有重复的行或列标签。但有时候比如通过 SQL 将数据存入数据库,就不能有重复的索引和列名,我们可以通过设置来限制重复索引:
df = pd.DataFrame({"A": [1, 2]}, index=['a', 'a'])
# 默认是允许重复的
df.flags["allows_duplicate_labels"] # True
df.flags.allows_duplicate_labels # True
df.flags
# <Flags(allows_duplicate_labels=True)>
# 已重复的就不能再设置为不重复的了
df.flags.allows_duplicate_labels = False
# DuplicateLabelError: Index has duplicates. positions....
# 生成时设置为标签为不可重复,后继操作就不能有重复的索引了
s = (pd.Series([1, 2], index=['a', 'b'])
.set_flags(allows_duplicate_labels=False)
)
s.reindex(['a', 'a'])
# DuplicateLabelError: Index has duplicates...
DataFrame 是二维的,有两个轴(axis,横向 1 或者纵向 0),每个方向上都有索引。索引都有名字(name,索引名),特别是在多层索引下,name 就显得特别重要。索引的取值索引值(标签值,label)是索引上每个行和列的具体值,也可叫标签值,有时简称标签。我们统一称索引名和索引值吧。基于此,总结下操作:
df.reindex(index=other.index, columns=other.columns,...)
我们用表格对几个修改索引名和索引值的方法进行对比:
方法 | 可按轴 axis | 修改索引名 name | 修改索引值 label | 是否需要原值 | 其他功能 |
---|---|---|---|---|---|
df.rename() |
是 | - | 是 | 是 | 支持映射 |
df.set_axis() |
是 | - | 是 | - | nan |
df.rename_axis() |
是 | 是 | - | 可有可无 | 支持映射 |
df.reindex() |
是 | - | 是 | - | 支持缺失值填充 |
df.reindex_like() |
必须同时 | - | 是 | - | 支持缺失值填充 |
更新时间:2024-10-23 20:24:42 标签:pandas 索引