numpy第三章-索引器、多级索引

一、索引器

df = pd.read_csv(....)

下面的df都是指数据名

1.列索引
从表中取出一列:df[‘列名’] 例如:df[‘Name’] 或者用 .列名 取出,这和 [列名] 是等价的(要求取出单列,且列名中不包含空格)例如:df.Name。

从表中取出多列:df[[‘列名1’,‘列名2’]] 例如:df[[‘Gender’, ‘Name’]]

2.行索引
【a】以字符串为索引
index 对应的每行索引

s = pd.Series([1, 2, 3, 4, 5, 6],
               index=['a', 'b', 'a', 'a', 'a', 'c'])
print(s)

输出:
在这里插入图片描述
行索引的应用,及多个索引

s['a']
Out[8]: 
a    1
a    3
a    4
a    5
dtype: int64

s['b']
Out[9]: 2

s[['c', 'b']]
Out[10]: 
c    6
b    2

切片:要取出两索引之间的元素时,可以考虑用切片,但要求这两个索引是在整个索引中唯一出现,同时这里的切片会包含两个端点

s['c': 'b': -2]
Out[11]: 
c    6
a    4
b    2
dtype: int64

如果前后端点的值存在重复,即非唯一值,那么需要经过排序才能使用切片:
直接s[‘a’: ‘b’]会报错,s.sort_index()[‘a’: ‘b’]结果为包括所有重复的两端点以及中间值

try:
    s['a': 'b']
except Exception as e:
    Err_Msg = e

Err_Msg
Out[13]: KeyError("Cannot get left slice bound for non-unique label: 'a'")

s.sort_index()['a': 'b']
Out[14]: 
a    1
a    3
a    4
a    5
b    2
dtype: int64

【b】以整数为索引
其他的同字符串为索引,但在切片中,则会取出对应索引 位置 的值,注意这里的整数切片同 Python 中的切片一样不包含右端点

s = pd.Series(['a', 'b', 'c', 'd', 'e', 'f'],
              index=[1, 3, 1, 2, 5, 4])
#[1:-1:2] 先指位置坐标从1到最后一个,不包括最后一个,这里指第2,4个
#转化为s[[3,2]] 
s[1:-1:2]
Out[18]: 
3    b
2    d

3.loc索引器
对于表而言,有两种索引器,一种是基于 元素 的 loc 索引器,另一种是基于 位置 的 iloc 索引器。

loc 索引器的一般形式是 loc[*, ] ,其中第一个 * 代表行的选择,第二个 * 代表列的选择,如果省略第二个位置写作 loc[] ,这个 * 是指行的筛选。其中, * 的位置一共有五类合法对象,分别是:单个元素、元素列表、元素切片、布尔列表以及函数,下面将依次说明。

为了演示相应操作,先利用 set_index 方法把 Name 列设为索引,关于该函数的其他用法将在多级索引一章介绍。

把某一行设置为索引行:df.set_index(‘列名’)

df_demo = df.set_index('Name')

df_demo.head()
  • 为单个元素,如果该元素在索引中重复则结果为 DataFrame,否则为 Series :
df_demo.loc['Qiang Sun'] # 多个人叫此名字,所以显示多行
Out[21]: 
                                  School      Grade  Gender  Weight Transfer
Name                                                                        
Qiang Sun            Tsinghua University     Junior  Female    53.0        N
Qiang Sun            Tsinghua University  Sophomore  Female    40.0        N
Qiang Sun  Shanghai Jiao Tong University     Junior  Female     NaN        N

df_demo.loc['Quan Zhao'] # 名字唯一
Out[22]: 
School      Shanghai Jiao Tong University
Grade                              Junior
Gender                             Female
Weight                               53.0
Transfer                                N

也可以同时选择行和列:

df_demo.loc['Qiang Sun', 'School'] # 返回Series
#即显示索引列name为'Qiang Sun'时的,列'School'取值
Out[23]: 
Name
Qiang Sun              Tsinghua University
Qiang Sun              Tsinghua University
Qiang Sun    Shanghai Jiao Tong University
Name: School, dtype: object

df_demo.loc['Quan Zhao', 'School'] # 返回单个元素
Out[24]: 'Shanghai Jiao Tong University'
#索引行取值:['Qiang Sun','Quan Zhao'],显示对应列['School','Gender']的值
df_demo.loc[['Qiang Sun','Quan Zhao'], ['School','Gender']]
  • 为切片,如果是唯一值的起点和终点字符,那么就可以使用切片,并且包含两个端点,如果不唯一则报错
    |(或), &(且), ~(取反)
df_demo.loc[lambda x: slice('Gaojuan You', 'Gaoqiang Qian')]

由于函数无法返回如 start: end: step 的切片形式,故返回切片时要用 slice 对象进行包装

4. iloc索引器
iloc 的使用与 loc 完全类似,只不过是针对位置进行筛选,在相应的 * 位置处一共也有五类合法对象,分别是:整数、整数列表、整数切片、布尔列表以及函数,函数的返回值必须是前面的四类合法对象中的一个

df_demo.iloc[1, 1] # 第二行第二列
Out[54]: 'Freshman'

df_demo.iloc[[0, 1], [0, 1]] # 前两行前两列
df_demo.iloc[1: 4, 2:4] # 切片不包含结束端点
df_demo.iloc[lambda x: slice(1, 4)] # 传入切片为返回值的函数

在使用布尔列表的时候要特别注意,不能传入 Series 而必须传入序列的 values ,否则会报错。因此,在使用布尔筛选的时候还是应当优先考虑 loc 的方式。

例如,选出体重超过80kg的学生:

df_demo.iloc[(df_demo.Weight>80).values].head()

5,query方法
例如查询体重超过均值的学生:

df.query('Weight > Weight.mean()').head()

在 query 中还注册了若干英语的字面用法,帮助提高可读性,例如: or, and, or, in, not in 。例如,筛选出男生中不是大一大二的学生:

df.query('(Grade not in ["Freshman", "Sophomore"]) and'
         '(Gender == "Male")').head()

在字符串中出现与列表的比较时, == 和 != 分别表示元素出现在列表和没有出现在列表,等价于 in 和 not in,例如查询所有大三和大四的学生:

df.query('Grade == ["Junior", "Senior"]').head()

对于 query 中的字符串,如果要引用外部变量,只需在变量名前加 @ 符号。例如,取出体重位于70kg到80kg之间的学生:

low, high =70, 80
df.query('(Weight >= @low) & (Weight <= @high)').head()

6.随机抽样
想要对样本或特征进行随机抽样就可以用 sample 函数

sample 函数中的主要参数为 n, axis, frac, replace, weights ,前三个分别是指抽样数量、抽样的方向(0为行、1为列)和抽样比例(0.3则为从总体中抽出30%的样本),replace 和 weights 分别是指是否放回和每个样本的抽样相对概率,当 replace = True 则表示有放回抽样
例如:对下面构造的 df_sample 以 value 值的相对大小为抽样概率进行有放回抽样,抽样数量为3

df_sample = pd.DataFrame({'id': list('abcde'),
                          'value': [1, 2, 3, 4, 90]})


df_sample
Out[68]: 
  id  value
0  a      1
1  b      2
2  c      3
3  d      4
4  e     90

df_sample.sample(3, replace = True, weights = df_sample.value)
Out[69]: 
  id  value
4  e     90
4  e     90
4  e     90

二、多级索引

1. 多级索引及其表的结构
与单层索引的表一样,具备元素值、行索引和列索引三个部分,只不过 索引中的一个元素是元组 而不是单层索引中的标量。例如,行索引的第四个元素为 (“B”, “Male”) ,列索引的第二个元素为 (“Height”, “Senior”)
在这里插入图片描述

与单层索引类似, MultiIndex 也具有名字属性,图中的 School 和 Gender 分别对应了表的第一层和第二层行索引的名字, Indicator 和 Grade 分别对应了第一层和第二层列索引的名字。

索引的名字和值属性分别可以通过 names 和 values 获得:

df_multi.index.names  #列索引名字
Out[75]: FrozenList(['School', 'Gender'])

df_multi.columns.names   #行索引名
Out[76]: FrozenList(['Indicator', 'Grade'])

df_multi.index.values    #列索引值
Out[77]: 
array([('A', 'Female'), ('A', 'Male'), ('B', 'Female'), ('B', 'Male'),
       ('C', 'Female'), ('C', 'Male'), ('D', 'Female'), ('D', 'Male')],
      dtype=object)

df_multi.columns.values   #行索引值
Out[78]: 
array([('Height', 'Freshman'), ('Height', 'Senior'),
       ('Height', 'Sophomore'), ('Height', 'Junior'),
       ('Weight', 'Freshman'), ('Weight', 'Senior'),
       ('Weight', 'Sophomore'), ('Weight', 'Junior')], dtype=object)

如果想要得到某一层的索引,则需要通过 get_level_values 获得,可以查找得到取值,但不能修改

df_multi.index.get_level_values(0)  #数据名.index.get_values(0)第一层列索引的取值
Out[79]: Index(['A', 'A', 'B', 'B', 'C', 'C', 'D', 'D'], dtype='object', name='School')

五、练习

第一题
在这里插入图片描述
1.分别只使用 query 和 loc 选出年龄不超过四十岁且工作部门为 Dairy 或 Bakery 的男性。

df = pd.read_csv('data/company.csv')
dpt = ['Dairy', 'Bakery']
df.query("(age <= 40)&(department == @dpt)&(gender=='M')")
#query与loc的用法
df.loc[(df.age<=40)&df.department.isin(dpt)&(df.gender=='M')]

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

df.iloc[(df.EmployeeID%2==1).values,[0,2,-2]]
df_op = df.copy()  #复制备份

#set.index()设置索引列,swaplevel()交换列/行位置
df_op = df_op.set_index(df_op.columns[-3:].tolist()).swaplevel(0,2,axis=0)

#恢复中间层索引
df_op = df_op.reset_index(level=1)
#rename_axis()修改列名
df_op = df_op.rename_axis(index={'gender':'Gender'})
#'_'.join(x)用下划线连接起来
df_op.index = df_op.index.map(lambda x:'_'.join(x))
#x.split('_')根据下划线进行拆分
df_op.index = df_op.index.map(lambda x:tuple(x.split('_')))
#再改列名
df_op = df_op.rename_axis(index=['gender', 'department'])
#reset_index()
df_op = df_op.reset_index().reindex(df.columns, axis=1)

df_op.equals(df)
Out[64]: True

第二题
在这里插入图片描述
1.把列索引名中的 \n 替换为空格

df = pd.read_csv('data/chocolate.csv')
#将列名根据'\n'拆开split,再用空格连接起来join
df.columns = [' '.join(i.split('\n')) for i in df.columns]

df.head(3)
Out[67]: 
    Company  Review Date Cocoa Percent Company Location  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

2.巧克力 Rating 评分为1至5,每0.25分一档,请选出2.75分及以下且可可含量 Cocoa Percent 高于中位数的样本。

df['Cocoa Percent'] = df['Cocoa Percent'].apply(lambda x:float(x[:-1])/100)
#2.75分及以下(即小于3)
df.query('(Rating<3)&(`Cocoa Percent`>`Cocoa Percent`.median())').head(3)

3.将 Review Date 和 Company Location 设为索引后,选出 Review Date 在2012年之后且 Company Location 不属于 France, Canada, Amsterdam, Belgium 的样本。

idx = pd.IndexSlice
exclude = ['France', 'Canada', 'Amsterdam', 'Belgium']
#set_index 设置索引列
res = df.set_index(['Review Date', 'Company Location']).sort_index(level=0)
#isin  后取非~  即不属于
res.loc[idx[2012:,~res.index.get_level_values(1).isin(exclude)],:]
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值