Task03_索引

一、索引器

对于DataFrame对象最常见的索引方式为df['column name']或者df[column list],前者返回的是一个Series,后者是DataFrameSeries对象索引的方式大概也是类似的,不再赘述

Pandas中还提供了一些特殊的函数和索引器来满足不同场景的需要

1.loc索引器

loc索引器一般形式为loc[*,*],前一个是行的选择,后一个是列的选择,后一个*的位置可以省略,A和B有五类合法对象:(后面为示例)

  • 单个元素:df.loc['index name']
  • 元素列表:df.loc[[index list], [column list]]
  • 元素切片:df.loc[:,:]前一个为行切片,后一个为列切片
  • 布尔列表以及函数:df.loc[df.Weight > 70]筛选体重大于70的数据所在行,需要注意的是,这里支持多个条件,使用逻辑运算符号即可

多级索引loc的用法和单级索引类似,只需要把标量换成对应的元组即可,还有一点需要注意的是:多级索引切片需要对索引进行排序,否则会报错

练一练

select_dtypes 是一个实用函数,它能够从表中选出相应类型的列,若要选出所有数值型的列,只需使用 .select_dtypes('number') ,请利用布尔列表选择的方法结合 DataFramedtypes 属性在 learn_pandas 数据集上实现这个功能。

df_demo = df.set_index('Name')
df_demo.loc[:,df_demo.dtypes==object].head()
2.iloc索引器

ilocloc索引器类似,不同的是,iloc是针对位置进行筛选,相应的,也有五类合法对象 ,分别是:

  • 整数:df.iloc[1,1]第二行第二列
  • 整数列表:df.iloc[[0,1],[0,1]]前两行前两列
  • 整数切片:df.iloc[[0:2,0:2]]前两行前两列(左闭右开区间)
  • 函数:df.iloc[func]:根据func逻辑执行
  • 布尔列表:df.iloc[(df.Weight>80).values]:体重大于80的行,需要注意的是,这里不能传入Series,需要传入values,因为values其实相当于一个列表
3.IndexSlice对象

IndexSlice对象针对的是多级索引使用,作用是在索引重复的情况下也可以针对每层进行切片,并且可以将元组和布尔列表混合使用。

IndexSlice对象有两种使用形式,第一种为 loc[idx[*,*]] ,第二种为 loc[idx[*,*],idx[*,*]],具体用法如下:

idx = pd.IndexSlice
## loc[idx[*,*]]型,前一个表示行的选择,后一个表示列的选择,和传统的loc是一样的
df_ex.loc[idx['C':, ('D', 'f'):]] # :表示全选
df_ex.loc[idx[:'A', lambda x:x.sum()>0]] # 列和大于0


## loc[idx[*,*],idx[*,*]] 型,前一个 idx 指代的是行索引,后一个是列索引
df_ex.loc[idx[:'A', 'b':], idx['E':, 'e':]]

上述的idx语法可以类比列表的切片,不过需要说明的是,这是闭区间

二、索引常用方法

1.query方法

query方法还是挺有意思的,由用户将需要的数据转换成逻辑运算的形式,和SQL很相似,直接给出一个例子

## 筛选出姓名为a,体重小于70的数据所在行
df.query('(name == 'a') & (weight < 70))')

并且在其中还可以调用Series中的方法

## 筛选出体重大于均值的行
df.query('Weight > Weight.mean()').head()

除此之外,pandas还提供了一些关键字代替逻辑运算符:orandis innot in

## 查找所有大三和大四的学生
df.query('Grade is in ["Junior", "Senior"]')

如果需要引用外部变量,需要在变量名前加@符号

## 找到体重位于low和high之间的数据行
low, high =70, 80
df.query('Weight.between(@low, @high)')
2.随机抽样

对样本或特征进行随机抽样就可以用 sample 函数,sample 函数中的主要参数为 n, axis, frac, replace, weights ,前三个分别是指抽样数量、抽样的方向(0为行、1为列)和抽样比例(0.3则为从总体中抽出30%的样本)。

3.索引的交换和删除

交换由swaplevelreorder_levels完成,前者只能交换两个层,后者可以交换任意层,两个函数都可以指定axis参数,代表操作的是行还是列,0为行,1为列

df_ex.swaplevel(0,2,axis=1).head() # 列索引的第一层和第三层交换
df_ex.reorder_levels([2,0,1],axis=0).head() # 列表数字指代原来索引中的层

删除某一层的索引,可以使用droplevel方法,该方法需要指定删除的层级,并且可以通过axis参数指定操作的是行索引还是列索引

df_ex.droplevel(1,axis=1)
4.索引属性的修改

通过 rename_axis 可以对索引层的名字进行修改,常用的修改方式是传入字典的映射:

df_ex.rename_axis(index={'Upper':'Changed_row'},columns={'Other':'Changed_Col'}).head()

通过 rename 可以对索引的值进行修改,如果是多级索引需要指定修改的层号 level ,同时该函数也能接受函数作为参数,例子如下:

df_ex.rename(columns={'cat':'not_cat'},level=2).head()

df_ex.rename(index=lambda x:str.upper(x),level=2).head()
练一练

尝试在 rename_axis 中使用函数完成与例子中一样的功能。

df_multi_demo.rename_axis(index=lambda x:str.upper(x))

map函数也可以实现索引属性的修改,参数为函数,例子如下:

## 实现某一属性名转大写
new_idx = df_temp.index.map(lambda x: (x[0],x[1],str.upper(x[2])))
4.索引的设置与重置

构造索引方式常见的有set_index[index column]set_index可以构造单级索引和多级索引,通过reset_index可以重置索引,该函数的drop=True/False参数可以选择是否丢弃去掉的索引。

除此之外还有一些构造多级索引的方式:

  • pd.MultiIndex.from_tuples:根据传入的由元组组成的列表进行构造
  • pd.MultiIndex.from_arrays:根据传入的列表构造
  • ``pd.MultiIndex.from_product`:根据给定的多个列表的笛卡尔积进行构造

例子如下:

my_tuple = [('a','cat'),('a','dog'),('b','cat'),('b','dog')]
my_array = [list('aabb'), ['cat', 'dog']*2]

my_list1 = ['a','b']
my_list2 = ['cat','dog']
pd.MultiIndex.from_product([my_list1,my_list2],names=['First','Second'])
5.索引的变形

reindex_like与函数其类似的功能,实现是仿照传入表的索引来对索引变形

df_existed = pd.DataFrame(index=['1001','1002','1003','1004'],columns['Weight','Gender'])
df_reindex.reindex_like(df_existed)

三、索引运算

经常会有一种利用集合运算来取出符合条件行的需求,例如有两张表 AB ,它们的索引都是员工编号,现在需要筛选出两表索引交集的所有员工信息,此时通过 Index 上的运算操作就很容易实现。

大概的运算方式为求交集、求并集、求差集等,对应的关系如下(id1id2分别代表):

  • id1.intersection(id2)id1id2的交集
  • id1.union(id2)id1id2并集
  • id1.different(id2):属于id1不属于id2
  • id1.symmetric_difference(id2)id1id2并集减去id1id2的交集

上述运算还可以用符号代替,比如&|^

若两张表需要做集合运算的列并没有被设置索引,一种办法是先转成索引,运算后再恢复,另一种方法是利用 isin 函数,例如在重置索引的第一张表中选出id列交集的所在行:

## id1和id2都为列名
df_set_in_col_1[df_set_in_col_1.id1.isin(df_set_in_col_2.id2)]

四、练习

Ex1:

1.分别只使用 queryloc 选出年龄不超过四十岁且工作部门为 DairyBakery 的男性。

## 使用loc
df.loc[(df.age <= 40) & (df.department.isin(['Dairy','Bakery'])) & (df.gender=='M')]

## 使用query
df.query('(age <= 40) and (department==["Dairy", "Bakery"]) and (gender == "M")')

2.选出员工 ID 号 为奇数所在行的第1、第3和倒数第2列。

df_demo = df.loc[df.EmployeeID.values % 2 == 1]
df_demo.iloc[:,[1,3,-2]]

3.按照以下步骤进行索引操作:

  • 把后三列设为索引后交换内外两层
  • 恢复中间一层
  • 修改外层索引名为 Gender
  • 用下划线合并两层行索引
  • 把行索引拆分为原状态
  • 修改索引名为原表名称
  • 恢复默认索引并将列保持为原表的相对位置

第一问:

## 第一问
df_demo = df.set_index(['department','job_title','gender'])
df_demo.swaplevel(0,2,axis=0).head()

第二问:

df_demo.reset_index([1])

第三问:

df_demo.rename_axis(index={'gender':'Gender'})

第四问:

new_idx = df_demo.index.map(lambda x:(x[0]+'_'+x[1]))
df_demo.index = new_idx

第五问:

new_idx = df_demo.index.map(lambda x:tuple(x.split('_')))
df_demo.index = new_idx

第六问:

df_demo.rename_axis(['gender', 'department'],axis=0)

第七问:

df_demo.reset_index()
df_demo.reindex(columns=df.columns)
Ex2
In [169]: df = pd.read_csv('data/chocolate.csv')

In [170]: df.head(3)
Out[170]: 
    Company  Review\nDate Cocoa\nPercent Company\nLocation  Rating
0  A. Morin          2016            63%            France    3.75
1  A. Morin          2015            70%            France    2.75
2  A. Morin          2015            70%            France    3.00
  1. 把列索引名中的 \n 替换为空格。
  2. 巧克力 Rating 评分为1至5,每0.25分一档,请选出2.75分及以下且可可含量 Cocoa Percent 高于中位数的样本。
  3. Review DateCompany Location 设为索引后,选出 Review Date 在2012年之后且 Company Location 不属于 France, Canada, Amsterdam, Belgium 的样本。

第一问:

df_demo = df.copy()
df_demo = df_demo.rename(columns=lambda x:str.replace(x,'\n',' '))

第二问:

df_demo['Cocoa Percent'] = df_demo['Cocoa Percent'].apply(lambda x:float(x[:-1]))
median = df_demo['Cocoa Percent'].median()
df_demo.loc[(df_demo.Rating <= 2.75) &(df_demo['Cocoa Percent'] > median)]

第三问:

idx = pd.IndexSlice
df_demo = df_demo.sort_index()
Location_diff = df_demo.index.get_level_values(1).unique().difference(['France','Canada','Amsterdam','Belgium'])
df_demo.loc[idx[2012:,Location_diff],:]
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值