首页
学习
活动
专区
圈层
工具
发布
50 篇文章
1
【原创佳作】介绍Pandas实战中一些高端玩法
2
pandas 如何实现 excel 中的汇总行?
3
pandas多级索引的骚操作!
4
40000字 Matplotlib 实操干货,真的全!
5
利用Python搞定女朋友的小情绪~
6
Python 绘制惊艳的瀑布图
7
6种方式创建多层索引
8
Python 进阶指南(编程轻松进阶):三、使用 Black 工具来格式化代码
9
数据科学 IPython 笔记本 9.6 聚合:最小、最大和之间的任何东西
10
精通 Pandas 探索性分析:1~4 全
11
高手系列!数据科学家私藏pandas高阶用法大全 ⛵
12
总结了67个pandas函数,完美解决数据处理,拿来即用!
13
PyAutoGUI,一个Python办公自动化利器!
14
解放双手|利用 PyAutoGUI 快速构建自动化操作脚本
15
Python中内置数据库!SQLite使用指南! ⛵
16
数据分析索引总结(中)Pandas多级索引
17
数据分析索引总结(下)Pandas索引技巧
18
数据分析索引总结(上)Pandas单级索引
19
网友需求系列01-Python-matplotlib定制化刻度(主副)绘制
20
用Python自动生成数据分析报告
21
手把手教你用Python操纵Word自动编写离职报告
22
pandas transform 数据转换的 4 个常用技巧!
23
30段极简Python代码:这些小技巧你都Get了么
24
数据处理遇到麻烦不要慌,5个优雅的Numpy函数助你走出困境
25
数据分析最有用的Top 50 Matplotlib图(带有完整的Python代码)(上)
26
数据分析最有用的Top 50 Matplotlib图(带有完整的Python代码)(下)
27
数据分析之Pandas变形操作总结
28
数据分析之Pandas缺失数据处理
29
数据分析之Pandas合并操作总结
30
数据分析之Pandas分组操作总结
31
学习用Pandas处理分类数据!
32
如何用Pandas处理文本数据?
33
Pandas处理时序数据(初学者必会)!
34
Python高阶函数使用总结!
35
机器学习在金融风控的经验总结!
36
你知道怎么用Pandas绘制带交互的可视化图表吗?
37
6个提升效率的pandas小技巧
38
Python数据分析库pandas高级接口dt和str的使用
39
pandas 拼接 concat 5 个常用技巧!
40
pandas分组8个常用技巧!
41
pandas 文本处理大全
42
pandas 筛选数据的 8 个骚操作
43
pandas 分类数据处理大全(附代码)
44
68 个Python内置函数,你用过几个?
45
太秀了!用 pandas 搞定 24 张 Excel 报表
46
用 Python 的 Template 类生成文件报告
47
码如其人,同学你能写一手漂亮的Python函数吗
48
Python处理图片九宫格,炫酷朋友圈
49
Python排序傻傻分不清?一文看透sorted与sort用法
50
python-docx操作word文件(
清单首页python文章详情

数据分析索引总结(下)Pandas索引技巧

作者:闫钟峰,Datawhale优秀学习者

寄语:本文对索引设定、常用索引型函数、重复元素处理、抽样函数等内容做了详细介绍。

索引设定

1. index_col参数

index_col是read_csv中的一个参数,而不是某一个方法,在使用 read_csv 函数读取文本的时候使用index_col参数指定用哪几个列作为索引

代码语言:javascript
复制
pd.read_csv('data/table.csv',index_col=['Address','School']).head()

2. reindex和reindex_like

reindex是指重新索引,它的重要特性在于索引对齐,很多时候用于重新排序。

代码语言:javascript
复制
df.head()

通过为reindex参数指定一个新的list,使得原始df的行重新排列。

代码语言:javascript
复制
df.reindex(index=sorted(list(df.index),reverse=True)).head()

如果传入的list是原始index的一个真子集, 则会实现分层抽样的效果

代码语言:javascript
复制
df.reindex(index=list(df.index)[::5])

为index传入的参数可以不是df的原始index中的值---这将引入缺失值构成的行,还可以传入重复索引。

代码语言:javascript
复制
df.reindex(index=[1101,1101,1203,1206,2402])

为columns传入参数,将对列索引做类似的事情。

代码语言:javascript
复制
df.reindex(columns=['Height','Height','Gender','Average']).head()

同时为index和columns传入原始index和columns 的真子集, 同样可以实现获取原始df的子df的目的。由于reindex的copy参数默认值是True,这时会返回一个新的变量,而不是修改原始df。

代码语言:javascript
复制
df.reindex(index=[1101,1203,2402],columns=['Height','Gender'])

可以选择缺失值的填充方法:

fill_value和method(bfill/ffill/nearest),其中method参数必须索引单调。bfill表示用所在索引1206的后一个有效行填充,ffill为前一个有效行。

代码语言:javascript
复制
df.reindex(index=[1101,1203,1206,2402],method='bfill')

数值上1205比1301更接近1206,因此用前者填充。nearest的最近, 是指在原始df中离得最近的,这个离得最近的可能并没有在被 reindex 的时候选中。

代码语言:javascript
复制
df.reindex(index=[1101,1203,1206,2402,1205,1301],method='nearest')

reindex_like的作用为生成一个横纵索引完全与参数列表一致的DataFrame,数据使用被调用的表。

代码语言:javascript
复制
df_temp = pd.DataFrame({'Weight':np.zeros(5),
                        'Height':np.zeros(5),
                        'ID':[1101,1104,1103,1106,1102]}).set_index('ID')

表中的值数据来自于df_temp, 而行索引和列索引则来自于传入的 df[0:5][['Weight','Height']]。由于df_temp中没有1105这个行索引,因此会引入缺失值。

代码语言:javascript
复制
df_temp.reindex_like(df[0:5][['Weight','Height']])

使用reindex方法实现上述reindex_like的效果--reindex_like可以看作是该方法的语法糖。

代码语言:javascript
复制
df_temp.reindex(index=df[0:5][['Weight','Height']].index,columns=df[0:5][['Weight','Height']].columns)

如果df_temp单调还可以使用method参数。

代码语言:javascript
复制
df_temp = pd.DataFrame({'Weight':range(5),
                        'Height':range(5),
                        'ID':[1101,1104,1103,1106,1102]}).set_index('ID').sort_index()

可以自行检验这里的1105的值是否是由bfill规则填充

代码语言:javascript
复制
df_temp.reindex_like(df[0:5][['Weight','Height']],method='bfill')

注意是用1105这个索引在df.temp中的前边或后边的值进行填充,

代码语言:javascript
复制
df_temp.reindex_like(df[0:5][['Weight','Height']],method='ffill')

使用reindex实现相同的效果。

代码语言:javascript
复制
df_temp.reindex(index=df[0:5][['Weight','Height']].index,columns=df[0:5][['Weight','Height']].columns,method='ffill')

3. set_index和reset_index

先介绍set_index:从字面意思看,就是将某些列作为索引。使用表内列作为索引:

代码语言:javascript
复制
df.head()

将df的列设置为索引, 参数 drop 默认丢弃原来的索引。

代码语言:javascript
复制
df.set_index('Class').head()

利用append参数可以将当前索引维持不变

这种情况下会把新的索引作为次级索引。

代码语言:javascript
复制
df.set_index('Class',append=True).head()

使用与表长相同的列作为索引(需要先转化为Series,否则报错)

代码语言:javascript
复制
df.set_index(pd.Series(range(df.shape[0]))).head()

如果恰好列名是用的默认整数索引, 并且包含了传入的参数,是否这些列会被设置成索引?

代码语言:javascript
复制
df_=pd.DataFrame(np.random.randn(24).reshape((3,8)))
df_.set_index(list(range(df_.shape[0])))
# 传入参数是 range(df_.shape[0] 时会报错:
# KeyError: 'None of [range(0, 3)] are in the columns'
# 当给 set_index 传入的是list的时候, 就会把列名和list一致的列设置为索引

看参数说明,并不一定需要Series

代码语言:javascript
复制
df.set_index(np.arange(df.shape[0])).head()

可以直接添加多级索引:

传入由多个类似 Series 的元素构成的list, 就会用这个多个类Series的元素作为多级索引。

代码语言:javascript
复制
df.set_index([pd.Series(range(df.shape[0])),pd.Series(np.ones(df.shape[0]))]).head()

下面介绍reset_index方法,它的主要功能是将索引重置为df的列

默认状态直接恢复到自然数索引:

代码语言:javascript
复制
df.reset_index().head()

多级索引时用level参数指定哪一层被reset,用col_level参数指定将索引名称set到多重列索引的哪一层:

代码语言:javascript
复制
L1,L2 = ['A','B','C'],['a','b','c']
mul_index1 = pd.MultiIndex.from_product([L1,L2],names=('Upper', 'Lower'))
L3,L4 = ['D','E','F'],['d','e','f']
mul_index2 = pd.MultiIndex.from_product([L3,L4],names=('Big', 'Small'))
df_temp = pd.DataFrame(np.random.rand(9,9),index=mul_index1,columns=mul_index2)

将编号为1的行索引(也就是次级索引)重置为列, 原来的次级索引名作为列索引的编号为0(也就是列索引的顶级索引),这时该列的次级列索引为空。

代码语言:javascript
复制
df_temp1 = df_temp.reset_index(level=1,col_level=0)

移出最内层索引

代码语言:javascript
复制
df_temp1.index

4. rename_axis和rename

rename_axis是针对多级索引的方法,作用是修改某一层索引的索引名(index.name),而不是索引的索引值(索引标签)

这里为index和columns传入的均是一个字典,键为原来的索引名称,值为新的索引名称。

代码语言:javascript
复制
df_temp.rename_axis(index={'Lower':'LowerLower'},columns={'Big':'BigBig'})

还可以直接使用赋值语句修改或命名索引--当原始索引并没有名字的时候,这种方式更加便捷。

代码语言:javascript
复制
df_temp.index.names=['UPPER','LOWER']
代码语言:javascript
复制
dftemp=pd.DataFrame(np.random.randn(20).reshape(10,2), index=pd.MultiIndex.from_tuples(list(np.random.randint(1,5,30).reshape(-1,3)))).sort_index()

由于索引的name为空,因此使用rename_index无法将其重命名。

代码语言:javascript
复制
dftemp.rename_axis(index={0:'LEFT',2:'RIGHT'},)

但是用赋值语句可以修改各层级索引的名字---能否只修改某一层级的索引的名字?

代码语言:javascript
复制
dftemp.index.names=['LEFT','MIDDLE','RIGHT']

重置dftemp

代码语言:javascript
复制
dftemp=pd.DataFrame(np.random.randn(20).reshape(10,2), index=pd.MultiIndex.from_tuples(list(np.random.randint(1,5,30).reshape(-1,3)))).sort_index()

但是用赋值语句可以修改各层级索引的名字---可以只修改某一层级的索引的名字?

代码语言:javascript
复制
# 传入一个和索引层级等长的list, 不需要命名的层级赋值 None, 需要命名的层级传入字符串
dftemp.index.names=[None,None,'RIGHT']

当然非层次化索引也可以用rename_axis重命名索引名。

代码语言:javascript
复制
df_temp1.rename_axis(index={'Upper':'UPPER'})

rename方法用于修改列或者行索引标签,而不是索引名

给index传入的字典,键是原来的索引值, 值是新的索引值。无需指定要修改的索引级别,会自动寻找索引中的相应的值----当不同层级的索引有相同的值的时候,这会造成混乱。

代码语言:javascript
复制
df_temp.rename(index={'A':'T'},columns={'e':'changed_e'}).head()

当不同层级的索引有相同的值的时候,这会造成混乱。

代码语言:javascript
复制
L1,L2 = ['A','B','C'],['a','b','c']
mul_index1 = pd.MultiIndex.from_product([L1,L1],names=('Upper1', 'Upper2'))
L3,L4 = ['D','E','F'],['d','e','f']
mul_index2 = pd.MultiIndex.from_product([L3,L4],names=('Big', 'Small'))
df_t = pd.DataFrame(np.random.rand(9,9),index=mul_index1,columns=mul_index2)

当不同层级的索引有相同的值的时候,这会造成混乱--注意行索引的每一层的 A 都被改为了 T。

代码语言:javascript
复制
df_t.rename(index={'A':'T'},columns={'e':'changed_e'}).head()
代码语言:javascript
复制
# 如果要同时修改行索引的第二层,以及列索引的第一层,怎么指定level?
代码语言:javascript
复制
df_t.rename(index={'A':'T'},level=1,columns={'E':'changed_e'},level=0).head()
# 显然不能同时指定两个level

一个问题:如果不同层级的索引的索引值有相同的值的时候,要想修改特定级别的索引的索引值(比如次级索引中的A,修改为a),需要如何修改?

答:使用参数level=1指定需要修改的层级为次级索引

代码语言:javascript
复制
df_t.rename(index={'A':'T'},columns={'e':'changed_e'},level=1).head()

常用索引型函数

1. where函数

当对条件为False的单元进行填充,不满足条件的行全部被设置为NaN

代码语言:javascript
复制
df.where(df['Gender']=='M').head()

注意和query的区别

代码语言:javascript
复制
df.query('Gender=="M"').head()

where函数需要增加一个dropna()才会和query等价,通过这种方法筛选结果和[ ]操作符的结果完全一致。

代码语言:javascript
复制
df.where(df['Gender']=='M').dropna().head()

[] 操作符--实际上是传入了布尔值索引。

代码语言:javascript
复制
df[df['Gender']=='M'].head()

第一个参数con为布尔条件,第二个参数other为填充值

代码语言:javascript
复制
df.where(df['Gender']=='M',np.random.rand(df.shape[0],df.shape[1])).head()

2. mask函数

mask函数与where功能上相反,其余完全一致,即对条件为True的单元进行填充

代码语言:javascript
复制
df.mask(df['Gender']!='M').dropna().head()
df.mask(df['Gender']!='M',np.random.rand(df.shape[0],df.shape[1])).head()

3. query函数

query函数中的布尔表达式中,下面的符号都是合法的:行列索引名、字符串、and / not / or / & / | / ~ / not in / in /==/!=、四则运算符。

代码语言:javascript
复制
df.query('(Address in ["street_6","street_7"])&(Weight>(70+10))&(ID in [1303,2304,2402])')

实际上就是根据列值满足的条件筛选行---基本上和sql里的where子句对应。注意传入的参数是带引号的

重复元素处理

1. duplicated方法

该方法返回了是否重复的布尔列表。

代码语言:javascript
复制
df.duplicated('Class').head()

可选参数keep默认为first,即首次出现设为不重复,若为last,则最后一次设为不重复,若为False,则所有重复项为False。

代码语言:javascript
复制
df.duplicated('Class',keep='last').tail()
df.duplicated('Class',keep=False).head() # - False : Mark all duplicates as ``True``.

2. drop_duplicates方法

从名字上看出为剔除重复项,这在后面章节中的分组操作中可能是有用的,例如需要保留每组的第一个值:

代码语言:javascript
复制
df.drop_duplicates('Class')

上边有些类似于mysql中按某列groupby之后,还能选择其他的非分组列。

代码语言:javascript
复制
df.drop_duplicates('Class',keep='last')

在传入多列时等价于将多列共同视作一个多级索引,比较重复项:

代码语言:javascript
复制
df.drop_duplicates(['School','Class'])

抽样函数

这里的抽样函数指的就是sample函数

1. n为样本量

代码语言:javascript
复制
df.sample(n=5)
df.sample(9)#由于是第一个参数,可以省略 n=

2. frac为抽样比

代码语言:javascript
复制
df.sample(frac=0.05)

3. replace为是否放回

代码语言:javascript
复制
df.sample(n=df.shape[0],replace=True).head()
# 有放回(replace=True)可以选择比df长度更多的元素回来
len(df.sample(n=123,replace=True)),len(df)
df.sample(n=35,replace=True).index.is_unique

4. axis为抽样维度,默认为0,即抽行

代码语言:javascript
复制
# axis=1 对列进行抽样
df.sample(n=3,axis=1).head()

5. weights为样本权重,自动归一化

代码语言:javascript
复制
w=np.random.rand(df.shape[0])
df.sample(n=3,weights=w).head()

以某一列为权重,这在抽样理论中很常见

代码语言:javascript
复制
df.sample(n=3,weights=df['Math']).head()

以某一列为权重,这在抽样理论中很常见--本质上是以这一列的列值为权重

代码语言:javascript
复制
df.sample(n=3,weights=df['Math'].values).head()
下一篇
举报
领券