首先导入所需的包
import numpy as np
import pandas as pd
一、索引器
1. 表的列索引
列索引是最常见的索引形式,一般通过 []
来实现。通过 [列名]
可以从 DataFrame
中取出相应的列,返回值为 Series
,例如从表中取出姓名一列:
如果要取出多个列,则可以通过[列名组成的列表]
,其返回值为一个DataFrame
,例如从表中取出性别和姓名两列:
【注意】当[]
里面是列名,返回Series。当[]
里面是列名组成的列表,返回DataFrame
此外,若要取出单列,且列名中不包含空格,则可以用.列名
取出,这和[列名]
是等价的:
2. 序列的行索引
【a】以字符串为索引的 Series
如果取出单个索引的对应元素,则可以使用 [item]
,若 Series
只有单个值对应,则返回这个标量值,如果有多个值对应,则返回一个 Series
:
如果取出多个索引的对应元素,则可以使用[items的列表]
:
如果想要取出某两个索引之间的元素,并且这两个索引是在整个索引中唯一出现,则可以使用切片,同时需要注意这里的切片会包含两个端点:
【注意】索引必须是唯一的,不然会报错。
【b】以整数为索引的Series
在使用数据的读入函数时,如果不特别指定所对应的列作为索引,那么会生成从0开始的整数索引作为默认索引。当然,任意一组符合长度要求的整数都可以作为索引。
和字符串一样,如果使用[int]
或[int_list]
,则可以取出对应索引元素的值:
如果使用整数切片,则会取出对应索引位置的值,注意这里的整数切片同Python
中的切片一样不包含右端点:
【注意】
1.这里面的整数不代表Series的索引,是代表的位置。从左到右0,1,2,…,从右到左-1,-2,…。
2.第三位数字代表步长,默认为1。
【WARNING】关于索引类型的说明
如果不想陷入麻烦,那么请不要把纯浮点以及任何混合类型(字符串、整数、浮点类型等的混合)作为索引,否则可能会在具体的操作时报错或者返回非预期的结果,并且在实际的数据分析中也不存在这样做的动机。
3. loc索引器
前面讲到了对DataFrame
的列进行选取,下面要讨论其行的选取。对于表而言,有两种索引器,一种是基于元素的loc
索引器,另一种是基于位置的iloc
索引器。
loc
索引器的一般形式是loc[*, *]
,其中第一个*
代表行的选择,第二个*
代表列的选择,如果省略第二个位置写作loc[*]
,这个*
是指行的筛选。其中,*
的位置一共有五类合法对象,分别是:单个元素、元素列表、元素切片、布尔列表以及函数,下面将依次说明。
为了演示相应操作,先利用set_index
方法把Name
列设为索引,关于该函数的其他用法将在多级索引一章介绍。
【a】*
为单个元素
此时,直接取出相应的行或列,如果该元素在索引中重复则结果为DataFrame
,否则为Series
:
也可以同时选择行和列:
【注意】行列的元素至多只能一个
【b】*
为元素列表
此时,取出列表中所有元素值对应的行或列:
注意:*
为元素列表时,必定返回DataFrame
【c】*
为切片
之前的Series
使用字符串索引时提到,如果是唯一值的起点和终点字符,那么就可以使用切片,并且包含两个端点,如果不唯一则报错:
需要注意的是,如果DataFrame
使用整数索引,其使用整数切片的时候和上面字符串索引的要求一致,都是元素切片,包含端点且起点、终点不允许有重复值。
下例证明了loc的整数索引与字符串索引的要求一致,都是元素切片,不是按照位置来切片。
【d】*
为布尔列表
在实际的数据处理中,根据条件来筛选行是极其常见的,此处传入loc
的布尔列表与DataFrame
长度相同,且列表为True
的位置所对应的行会被选中,False
则会被剔除。
例如,选出体重超过70kg的学生(和用[]
结果一致):
前面所提到的传入元素列表,也可以通过isin
方法返回的布尔列表等价写出,例如选出所有大一和大四的同学信息:
.isin()
判断元素在不在()里的序列中。
对于复合条件而言,可以用|(或), &(且), ~(取反)
的组合来实现,例如选出复旦大学中体重超过70kg的大四学生,或者北大男生中体重超过80kg的非大四的学生:
【练一练】
select_dtypes
是一个实用函数,它能够从表中选出相应类型的列,若要选出所有数值型的列,只需使用.select_dtypes('number')
,请利用布尔列表选择的方法结合DataFrame
的dtypes
属性在learn_pandas
数据集上实现这个功能。
【e】*
为函数
这里的函数,必须以前面的四种合法形式之一为返回值,并且函数的输入值为DataFrame
本身。假设仍然是上述复合条件筛选的例子,可以把逻辑写入一个函数中再返回,需要注意的是函数的形式参数x
本质上即为df_demo
:
此外,还支持使用lambda
表达式,其返回值也同样必须是先前提到的四种形式之一:
由于函数无法返回如start: end: step
的切片形式,故返回切片时要用slice
对象进行包装:
第一次见到slice对象,下面简单介绍一下。
slice() 函数实现切片对象,主要用在切片操作函数里的参数传递。
class slice(start, stop[, step])
三个参数的含义分别是:起始位置,终止位置,间距
最后需要指出的是,对于Series
也可以使用loc
索引,其遵循的原则与DataFrame
中用于行筛选的loc[*]
完全一致,此处不再赘述。
【WARNING】不要使用链式赋值
在对表或者序列赋值时,应当在使用一层索引器后直接进行赋值操作,这样做是由于进行多次索引后赋值是赋在临时返回的copy
副本上的,而没有真正修改元素从而报出SettingWithCopyWarning
警告。例如,下面给出的例子:
4. iloc索引器
iloc
的使用与loc
完全类似,只不过是针对位置进行筛选,在相应的*
位置处一共也有五类合法对象,分别是:整数、整数列表、整数切片、布尔列表以及函数,函数的返回值必须是前面的四类合法对象中的一个,其输入同样也为DataFrame
本身。
见上例:传入两个list的时候,是第一行,第二行与第一列,第二列的交叉部分取出来。
只传入一个.iloc[i:j]
则只取出第i到j-1行
【注意】.iloc[i,j]
的i,j只要是列表则取出的必定为DataFrame,假如其中有一边为int,则返回Series
在使用布尔列表的时候要特别注意,不能传入Series
而必须传入序列的values
,否则会报错。因此,在使用布尔筛选的时候还是应当优先考虑loc
的方式。
例如,选出体重超过80kg的学生:
对Series
而言同样也可以通过iloc
返回相应位置的值或子序列(切片方法和python中一致):
5. query方法
在pandas
中,支持把字符串形式的查询表达式传入query
方法来查询数据,其表达式的执行结果必须返回布尔列表。在进行复杂索引时,由于这种检索方式无需像普通方法一样重复使用DataFrame
的名字来引用列名,一般而言会使代码长度在不降低可读性的前提下有所减少。
df.query(expr,inplace = False,** kwargs )# 使用布尔表达式查询列
参数:
# expr:str要评估的查询字符串。你可以在环境中引用变量,在它们前面添加一个'@'字符 。@a + b
# inplace=False:是否修改数据或返回副本
# kwargs:dict关键字参数
返回:DataFrame
注意:
# 默认修改Python语法'&'/'and'和'|'/'or'位运算符优先级高于布尔表达式,不同于Python
# 关键字参数parser='python'执行Python评估。
# engine='python' 用Python本身作为后端来传递评估表达式。不建议效率低。
# 默认实例df.index和 df.columns属性 DataFrame放在查询命名空间中,
# 这允许您将框架的索引和列视为框架中的列。标识符index用于帧索引;
# 您还可以使用索引的名称在查询中标识它。
例如,将loc
一节中的复合条件查询例子可以如下改写(注意下面的()
):
在query
表达式中,帮用户注册了所有来自DataFrame
的列名,所有属于该Series
的方法都可以被调用,和正常的函数调用并没有区别,例如查询体重超过均值的学生:
可以看到上面直接weight.mean() ,这里weight是df的列名,继承了这个Series的方法。
【NOTE】query中引用带空格的列名
对于含有空格的列名,要使用上面的语法,需要在列名左右加上`(反引号)。
同时,在query
中还注册了若干英语的字面用法,帮助提高可读性,例如:or, and, or, in, not in
。例如,筛选出男生中不是大一大二的学生:
此外,在字符串中出现与列表的比较时,==
和!=
分别表示元素出现在列表和没有出现在列表,等价于in
和not in
,例如查询所有大三和大四的学生:
对于query
中的字符串,如果要引用外部变量,只需在变量名前加@
符号。例如,取出体重位于70kg到80kg之间的学生:
这里一开始出现了一点问题
low, high =70, 80
df.query('Weight.between(@low, @high)').head()
这里是报错的,错误提示为'Series' objects are mutable, thus they cannot be hashed
然后做了第一次尝试:
对于此的理解是,df.query在python版本3.8的情况下,这种使用Series的相应方法产生的Series序列要取出对应布尔值—也就是np数组。下面看另一个这样的写法也是不对的。
list_grade=['Freshman','Sophomore']
df.query('Grade.isin(@list_grade)').head()
第二次尝试:
query里面加上engine='python’后也不会报错了。
再看一下别的例子
df11 = pd.DataFrame(np.arange(12).reshape(3, 4), columns=list('ABCD'))
# 实例1.1:python,numexpr 方式比较
result1 = df11[(df11.A < 8) & (df11.B < 9)] #python方式
result2 = pd.eval('df11[(df11.A < 8) & (df11.B < 9)]')#numexpr 方式
np.allclose(result1, result2) # True
# 实例1.2:eval,query,比较
# 相同点:计算表达式结果
# 不同点:eval若表达式为逻辑,结果返回bool数组;query则返回对应于bool数组的数据
import numexpr
result3= df11[df11.eval('A<8 & B<9')]
result4 = df11.query('A < 8 and B < 9')
result3.equals(result4) #True 结果result1==result2==result3==result4
a=df11.A;b=df11.B
result5= df11[numexpr.evaluate('(a<8) &(b < 9)')]#等效;表达式不能含df.A
pd.eval()就是把str转换为具体对象。
df11.eval('A<8 & B<9')
就等价为df11[A<8]&df11[B<9]
6. 随机抽样
如果把DataFrame
的每一行看作一个样本,或把每一列看作一个特征,再把整个DataFrame
看作总体,想要对样本或特征进行随机抽样就可以用sample
函数。有时在拿到大型数据集后,想要对统计特征进行计算来了解数据的大致分布,但是这很费时间。同时,由于许多统计特征在等概率不放回的简单随机抽样条件下,是总体统计特征的无偏估计,比如样本均值和总体均值,那么就可以先从整张表中抽出一部分来做近似估计。
sample
函数中的主要参数为n, axis, frac, replace, weights
,前三个分别是指抽样数量、抽样的方向(0为行、1为列)和抽样比例(0.3则为从总体中抽出30%的样本)。
replace
和weights
分别是指是否放回和每个样本的抽样相对概率,当replace = True
则表示有放回抽样。例如,对下面构造的df_sample
以value
值的相对大小为抽样概率进行有放回抽样和无放回抽样,抽样数量为3。
二、多级索引
1. 多级索引及其表的结构
为了更加清晰地说明具有多级索引的DataFrame
结构,下面新构造一张表,读者可以忽略这里的构造方法,它们将会在第4小节被更详细地讲解。
下图通过颜色区分,标记了DataFrame
的结构。与单层索引的表一样,具备元素值、行索引和列索引三个部分。其中,这里的行索引和列索引都是MultiIndex
类型,只不过索引中的一个元素是元组而不是单层索引中的标量。例如,行索引的第四个元素为("B", "Male")
,列索引的第二个元素为("Height", "Senior")
,这里需要注意,外层连续出现相同的值时,第一次之后出现的会被隐藏显示,使结果的可读性增强。
这里需要注意的是多层索引中的元素是一个元组!!!
与单层索引类似, MultiIndex
也具有名字属性,图中的 School
和 Gender
分别对应了表的第一层和第二层行索引的名字, Indicator
和 Grade
分别对应了第一层和第二层列索引的名字。
索引的名字和值属性分别可以通过 names
和 values
获得:
如果想要得到某一层的索引,则需要通过get_level_values
获得:
但对于索引而言,无论是单层还是多层,用户都无法通过index_obj[0] = item
的方式来修改元素,也不能通过index_name[0] = new_name
的方式来修改名字,关于如何修改这些属性的话题将在第三节被讨论。
2. 多级索引中的loc索引器
熟悉了结构后,现在回到原表,将学校和年级设为索引,此时的行为多级索引,列为单级索引,由于默认状态的列索引不含名字,因此对应于刚刚图中Indicator
和Grade
的索引名位置是空缺的。
由于多级索引中的单个元素以元组为单位,因此之前在第一节介绍的loc
和iloc
方法完全可以照搬,只需把标量的位置替换成对应的元组,不过在索引前最好对MultiIndex
进行排序以避免性能警告。:
这里排序之后就可以对重复元素进行切片(对单层索引和多层索引都适用)。但是不排序对多层索引切片都会报错。下面df_multi_sort是排序过的,df_multi是未排序的,df_multi_drop是去除重复索引(重复的保留第一个)
df_multi.loc[('Fudan University','Freshman'):('Tsinghua University','Sophomore')]
下面可以看到对没有重复的复合索引切片也会报错。
下面对其排序之后,切片索引不报错
此外,在多级索引中的元组有一种特殊的用法,可以对多层的元素进行交叉组合后索引,但同时需要指定loc
的列,全选则用:
表示。其中,每一层需要选中的元素用列表存放,传入loc
的形式为[(level_0_list, level_1_list), cols]
。例如,想要得到所有北大和复旦的大二大三学生,可以如下写出:
【理解】取出这四个索引:(Peking University,Sophomore),(Peking University,Junior)(Fudan University,Sophomore)(Fudan University,Junior)
下面的语句和上面类似,但仍然传入的是元素(这里为元组)的列表,它们的意义是不同的,表示的是选出北大的大三学生和复旦的大二学生:
这个就类似于单层索引里的df.loc[['a','b']]
a,b是index
3. IndexSlice对象
前面介绍的方法,即使在索引不重复的时候,也只能对元组整体进行切片,而不能对每层进行切片,也不允许将切片和布尔列表混合使用,引入IndexSlice
对象就能解决这个问题。Slice
对象一共有两种形式,第一种为loc[idx[*,*]]
型,第二种为loc[idx[*,*],idx[*,*]]
型,下面将进行介绍。为了方便演示,下面构造一个索引不重复的DataFrame
:
为了使用silce
对象,先要进行定义:
idx = pd.IndexSlice
【a】loc[idx[*,*]]
型
这种情况并不能进行多层分别切片,前一个*
表示行的选择,后一个*
表示列的选择,与单纯的loc
是类似的:
另外,也支持布尔序列的索引:
【b】loc[idx[*,*],idx[*,*]]
型
这种情况能够分层进行切片,前一个idx
指代的是行索引,后一个是列索引。
4. 多级索引的构造
前面提到了多级索引表的结构和切片,那么除了使用set_index
之外,如何自己构造多级索引呢?常用的有from_tuples, from_arrays, from_product
三种方法,它们都是pd.MultiIndex
对象下的函数。
4.1from_tuples
指根据传入由元组组成的列表进行构造:
4.2from_arrays
指根据传入列表中,对应层的列表进行构造:
4.3from_product
指根据给定多个列表的笛卡尔积进行构造:
【总结】
from_tuples
就是直接传入元祖。类似于直接传入index。
from_arrays
类似于第一个列表是第一层索引,第二个列表是第二个索引。
from_product
指根据给定多个列表的笛卡尔积进行构造。形成nXm个index。
这三个函数都要传入list。
三、索引的常用方法
1. 索引层的交换和删除
为了方便理解交换的过程,这里构造一个三级索引的例子:
索引层的交换由swaplevel
和reorder_levels
完成,前者只能交换两个层,而后者可以交换任意层,两者都可以指定交换的是哪一个轴,即行索引或列索引:
axis=1代表交换列索引,axis=0代表交换行索引
.reorder_levels()通过传入列表来指定哪几个轴更换,上例的意思是将[0,1,2]变为[2,0,1]
【NOTE】轴之间的索引交换
这里只涉及行或列索引内部的交换,不同方向索引之间的交换将在第五章中被讨论。
若想要删除某一层的索引,可以使用droplevel
方法:
可以看到想要删除多个行索引或列索引时,就传入含有int的列表
2. 索引属性的修改
通过rename_axis
可以对索引层的名字进行修改,常用的修改方式是传入字典的映射:
通过rename
可以对索引的值进行修改,如果是多级索引需要指定修改的层号level
:
上例将df_ex的第二层列索引的cat改为not_cat
传入参数也可以是函数,其输入值就是索引元素:
【练一练】
尝试在rename_axis
中使用函数完成与例子中一样的功能。
对于整个索引的元素替换,可以利用迭代器实现:
若想要对某个位置的元素进行修改,在单层索引时容易实现,即先取出索引的values
属性,再给对得到的列表进行修改,最后再对index
对象重新赋值。但是如果是多级索引的话就有些麻烦,一个解决的方案是先把某一层索引临时转为表的元素,然后再进行修改,最后重新设定为索引,下面一节将介绍这些操作。
另外一个需要介绍的函数是map
,它是定义在Index
上的方法,与前面rename
方法中层的函数式用法是类似的,只不过它传入的不是层的标量值,而是直接传入索引的元组,这为用户进行跨层的修改提供了遍历。例如,可以等价地写出上面的字符串转大写的操作:
关于map
的另一个使用方法是对多级索引的压缩,这在第四章和第五章的一些操作中是有用的:
同时,也可以反向地展开:
【总结】.rename()
与.rename_axis()
里传入函数是接收的每一层的标量值。而map
里传入函数是接收的每一个多层索引的元组。
3. 索引的设置与重置
为了说明本节的函数,下面构造一个新表:
索引的设置可以使用set_index
完成。
df_new.set_index(keys,drop=True,append=False,inplace=False, verify_integrity=False,)
append
表示是否来保留原来的索引,append=True时直接把新设定的添加到原索引的内层,drop表示是否将用作新索引的列删掉:
可以同时指定多个列作为索引(传入列表形式):
如果想要添加索引的列没有出现再其中,那么可以直接在参数中传入相应的Series
reset_index
是set_index
的逆函数,其主要参数是drop
,表示是否要把去掉的索引层丢弃,而不是添加到列中:
df_new.reset_index(level: Union[Hashable, Sequence[Hashable], NoneType] = None,
drop: bool = False,inplace: bool = False,
col_level: Hashable = 0,
col_fill: Union[Hashable, NoneType] = '')
如果重置了所有的索引,那么pandas
会直接重新生成一个默认索引:
最后来看多层索引的例子:
将’class’去掉:
col_level
参数规定其列索引的层级。
col_fill
参数用来填补为空的列索引
4. 索引的变形
在某些场合下,需要对索引做一些扩充或者剔除,更具体地要求是给定一个新的索引,把原表中相应的索引对应元素填充到新索引构成的表中。例如,下面的表中给出了员工信息,需要重新制作一张新的表,要求增加一名员工的同时去掉身高列并增加性别列:
这种需求常出现在时间序列索引的时间点填充以及ID
编号的扩充。另外,需要注意的是原来表中的数据和新表中会根据索引自动对其,例如原先的1002号位置在1003号之后,而新表中相反,那么reindex
中会根据元素对其,与位置无关。
还有一个与reindex
功能类似的函数是reindex_like
,其功能是仿照传入的表的索引来进行被调用表索引的变形。例如,现在以及存在一张表具备了目标索引的条件,那么上述功能可以如下等价地写出:
四、索引运算
1. 集合的运算法则
经常会有一种利用集合运算来取出符合条件行的需求,例如有两张表A
和B
,它们的索引都是员工编号,现在需要筛选出两表索引交集的所有员工信息,此时通过Index
上的运算操作就很容易实现。
不过在此之前,不妨先复习一下常见的四种集合运算:
S
A
.
i
n
t
e
r
s
e
c
t
i
o
n
(
S
B
)
=
S
A
∩
S
B
⇔
{
x
∣
x
∈
S
A
a
n
d
x
∈
S
B
}
\rm S_A.intersection(S_B) = \rm S_A \cap S_B \Leftrightarrow \rm \{x|x\in S_A\, and\, x\in S_B\}
SA.intersection(SB)=SA∩SB⇔{x∣x∈SAandx∈SB}
S
A
.
u
n
i
o
n
(
S
B
)
=
S
A
∪
S
B
⇔
{
x
∣
x
∈
S
A
o
r
x
∈
S
B
}
\rm S_A.union(S_B) = \rm S_A \cup S_B \Leftrightarrow \rm \{x|x\in S_A\, or\, x\in S_B\}
SA.union(SB)=SA∪SB⇔{x∣x∈SAorx∈SB}
S
A
.
d
i
f
f
e
r
e
n
c
e
(
S
B
)
=
S
A
−
S
B
⇔
{
x
∣
x
∈
S
A
a
n
d
x
∉
S
B
}
\rm S_A.difference(S_B) = \rm S_A - S_B \Leftrightarrow \rm \{x|x\in S_A\, and\, x\notin S_B\}
SA.difference(SB)=SA−SB⇔{x∣x∈SAandx∈/SB}
S
A
.
s
y
m
m
e
t
r
i
c
_
d
i
f
f
e
r
e
n
c
e
(
S
B
)
=
S
A
△
S
B
⇔
{
x
∣
x
∈
S
A
∪
S
B
−
S
A
∩
S
B
}
\rm S_A.symmetric\_difference(S_B) = \rm S_A\triangle S_B\Leftrightarrow \rm \{x|x\in S_A\cup S_B - S_A\cap S_B\}
SA.symmetric_difference(SB)=SA△SB⇔{x∣x∈SA∪SB−SA∩SB}
2. 一般的索引运算
由于集合的元素是互异的,但是索引中可能有相同的元素,先用unique
去重后再进行运算。下面构造两张最为简单的示例表进行演示:
上述的四类运算还可以用等价的符号表示代替如下:
若两张表需要做集合运算的列并没有被设置索引,一种办法是先转成索引,运算后再恢复,另一种方法是利用isin
函数,例如在重置索引的第一张表中选出id列交集的所在行:
其中df_set_in_col_1.id1.isin(df_set_in_col_2.id2)
返回布尔值
Ex1:公司员工数据集
现有一份公司员工数据集:
- 分别只使用
query
和loc
选出年龄不超过四十岁且工作部门为Dairy
或Bakery
的男性。 - 选出员工
ID
号 为奇数所在行的第1、第3和倒数第2列。 - 按照以下步骤进行索引操作:
- 把后三列设为索引后交换内外两层
- 恢复中间一层
- 修改外层索引名为
Gender
- 用下划线合并两层行索引
- 把行索引拆分为原状态
- 修改索引名为原表名称
- 恢复默认索引并将列保持为原表的相对位置
#1.1使用query方法
df.query('(age <= 40) and (department in ["Dairy","Bakery"]and(gender=="M"))')
#1.2使用iloc方法
condition_1 = df['age'] <= 40
condition_2 = df['department'].isin(["Dairy","Bakery"])
condition_3 = df['gender']=='M'
condition11 = condition_1 & condition_2 & condition_3
df[condition11]
# 第2问
df[df['EmployeeID']%2==1].iloc[:,[0,2,-2]]
#3.1 把后三列设为索引后交换内外两层
df.set_index(['department','job_title','gender']).swaplevel(0,2,axis=0)
# 3.2 恢复中间一层
df.set_index(['department','job_title','gender']).swaplevel(0,2,axis=0).reset_index('job_title')
# 3.3 修改外层索引名为 Gender
df.set_index(['department','job_title','gender']).swaplevel(0,2,axis=0).reset_index('job_title').rename_axis(index={'gender':'Gender'})
# 3.4 把后三列设为索引后交换内外两层
df_33 = df.set_index(['department','job_title', 'gender']).swaplevel(0,2,axis=0).reset_index('job_title').rename_axis(index={'gender':'Gender'})
df_34_index = df_33.index.map(lambda x : x[0]+'-'+x[1])
df_34 = df_33
df_34.index = df_34_index
df_34
#3.5 把行索引拆分为原状态
df_35=df_34
df_35.index=df_35.index.map(lambda x : tuple(x.split('-')))
#3.6 修改索引名为原表名称
df_36 = df_35.rename_axis(index=['gender','department'])
#3.7恢复默认索引并将列保持为原表的相对位置
df_36.reset_index().reindex_like(df)
Ex2:巧克力数据集
现有一份关于巧克力评价的数据集:
- 把列索引名中的
\n
替换为空格。 - 巧克力
Rating
评分为1至5,每0.25分一档,请选出2.75分及以下且可可含量Cocoa Percent
高于中位数的样本。 - 将
Review Date
和Company Location
设为索引后,选出Review Date
在2012年之后且Company Location
不属于France, Canada, Amsterdam, Belgium
的样本。
# 第1问
df=df.rename(columns=lambda x : str(x).replace('\n',' '))
# 第2问
df['Cocoa Percent']=df['Cocoa Percent'].apply(lambda x : int(x[0:2])/100)
df.query('(`Cocoa Percent` > `Cocoa Percent`.median())&(Rating <= 2.75)')
# 第3问
idx = pd.IndexSlice
df1=df.set_index(['Review Date','Company Location']).sort_index()
df1.loc[idx[2012:,~res.index.get_level_values(1).isin(exclude)],:]
五、总结
5.1索引器
索引比较繁琐,但整体思路就是①只选列用[]
②选位置用iloc
③选元素用loc
④偷懒想少写字用query
5.2 多层索引
多层索引的索引是一个元组,整体思路和单层索引类似。对多层索引切片时,第一步先排序。不然会报错!!!!
若想对每层进行切片有两个操作,indexslice
对象与loc中的特殊用法—对多层的元素进行交叉组合后索引,形式为[(level_0_list, level_1_list), cols]
其中indexslice对象,在loc[idx[*,*]]
型可以支持传入函数,但在loc[idx[*,*],idx[*,*]]
型不支持传入函数,后者可以支持分层进行切片,见EX2第二问。
多层索引的构造方法有三种:from_tuples, from_arrays, from_product
5.3索引的常用方法
索引层的交换:swaplevel
(只能换两个轴)和 reorder_levels
(可以换任意多个轴,传入新的轴顺序列表即可) ps:这里只是行索引与列索引内部的更换。
索引层的删除:droplevel
索引属性的修改:1.修改索引层名字 rename_axis
,可传入函数(函数的输入就是各个索引层名字)
2.修改索引值 rename
,多层索引时通过level传入所修改的层号。可传入函数(函数的输入就是某层索引值)
另外一个是定义在 Index
上的方法,也可以传入函数,但是与rename
不同的是:它传入的不是层的标量值,而是直接传入索引的元组。这就可以实现对多级索引的压缩和展开。
3.索引的设置与重置:set_index
与reset_index
4.索引的变形: reindex
与 reindex_like
,前者需要传入index
与columns
参数,后者只用传入需要仿照索引的DataFrame.
5.4 索引运算
.intersection
(交集&)
.union
(并集|)
.difference
(A-B)
.symmetric_difference
(对称差,^)