文章目录
内容介绍
这是第三篇打卡文章。
索引器
表的列索引
取单列数据
df['Name'].head()
取多列数据
df[['Gender', 'Name']].head()
loc索引器
loc的基本用法是df.loc[*]以及df.loc[*,*]
*可以替换为多种形式
df.loc[*]是选出部分行以及所有列
df.loc[*,*]是选出部分行和部分列
使用示例表格如上,名字作为行索引
类型 | 示例 | 备注 |
---|---|---|
单个元素 | df_demo.loc['Qiang Sun'] 以及df_demo.loc['Qiang Sun', 'School'] | |
元素列表 | df_demo.loc[['Qiang Sun','Quan Zhao'] , ['School','Gender']] | |
元素切片 | df_demo.loc['Gaojuan You':'Gaoqiang Qian', 'School':'Gender'] | 此时端点两侧需要是唯一的 |
布尔列表 | df_demo.loc[df_demo.Weight>70].head() | |
函数 | df_demo.loc[lambda x:'Quan Zhao', lambda x:'Gender'] | 可以自定义函数,也可以是用匿名函数,但是返回值需要是前面四种形式 |
iloc索引器
iloc的使用与loc完全类似,只不过是针对位置进行筛选,在相应的*位置处一共也有五类合法对象,分别是:整数、整数列表、整数切片、布尔列表以及函数,函数的返回值必须是前面的四类合法对象中的一个,其输入同样也为DataFrame本身。
类型 | 示例 | 备注 |
---|---|---|
整数 | df_demo.iloc[1, 1] | 第二行第二列 |
整数列表 | df_demo.iloc[[0, 1], [0, 1]] | 前两行前两列 |
整数切片 | df_demo.iloc[1: 4, 2:4] | 切片不包含结束端点 |
布尔列表 | df_demo.iloc[(df_demo.Weight>80).values].head() | 不能传入Series而必须传入序列的values |
函数 | df_demo.iloc[lambda x: slice(1, 4)] | 传入切片为返回值的函数 |
query方法
query利用传入字符串的形式查询表中数据,可以直接使用列名。当列名带空格时,需要使用`列名`。条件的连接直接需要使用and,or,in,not in,同时条件要用括号括起来
# 筛选体重大于平均值的行
df.query('Weight > Weight.mean()').head()
out:
随机抽样
当我们处理大型数据,想要使用聚合函数得到数据的统计学特征时,如果直接计算,时间开销太大,于是我们需要去使用抽样方法来作为整个数据的统计特征的一个近似。
所以我们使用sample方法,它的重要参数有n, axis, frac, replace, weights
参数 | 作用 |
---|---|
n | 抽样数量 |
axis | 抽样的方向,0为行、1为列 |
frac | 抽样比例 |
replace | 是否是有放回抽样 |
weights | 每个样本的抽样概率 |
df_sample = pd.DataFrame({'id': list('abcde'), 'value': [1, 2, 3, 4, 90]})
print(df_sample)
print('抽样结果')
# 利用value列做为抽样概率权重
df_sample.sample(3, replace = False, weights = df_sample.value)
out:
id value
0 a 1
1 b 2
2 c 3
3 d 4
4 e 90
抽样结果
id value
4 e 90
1 b 2
3 d 4
多级索引
多级索引以及表的结构
我们可以看到多级索引可以是行索引,也可以是列索引,在行索引是school,gender,列索引是Indicator,Grade,所以索引不再是一个单独的元素,而是由对应元素构成的元组
多级索引的相关属性
相关属性有names,values
如果想要获得某一层的索引,利用get_level_values()得到某一层的索引
多层索引中的loc
多层索引的loc方法与单层索引没有很大区别,只需要吧单独的元素换成一个元组。同时还需要注意的是筛选时要对索引进行排序,提高效率,避免警告。
# 利用set_index方法设置多重索引
df_multi = df.set_index(['School', 'Grade'])
# 先对数据进行排序,然后才能筛选
df_sorted = df_multi.sort_index()
df_sorted.loc[('Fudan University', 'Junior')].head()
同时还有一种特殊的用法,可以利用对各层的元素进行笛卡尔积的结果进行筛选
res = df_multi.loc[(['Peking University', 'Fudan University'], ['Sophomore', 'Junior']), :]
res.head()
IndexSlice对象的使用
即使在索引不重复的时候,也只能对元组整体进行切片,而不能对每层进行切片,也不允许将切片和布尔列表混合使用,引入IndexSlice对象就能解决这个问题。Slice对象一共有两种形式,第一种为loc[idx[*,*]]型,第二种为loc[idx[*,*],idx[*,*]]型
loc[idx[*,*]]型
这种情况并不能进行多层分别切片,前一个表示行的选择,后一个表示列的选择,与单纯的loc是类似的:
idx=pd.IndexSlice
df_ex.loc[idx['C':, ('D', 'f'):]]
out:
loc[idx[*,*],idx[*,*]]
这种情况能够分层进行切片,前一个idx指代的是行索引,后一个是列索引。
df_ex.loc[idx[:'B', 'a':'b'], idx['E':, 'e':]]
out:
但是此时不可以使用函数
多次索引的构造
有三种方法构造多层索引,分别是列表,元组,笛卡尔积
pd.MultiIndex.from_tuples
my_tuple = [('a','cat'),('a','dog'),('b','cat'),('b','dog')]
pd.MultiIndex.from_tuples(my_tuple, names=['First','Second'])
out
pd.MultiIndex.from_arrays
my_array = [list('aabb'), ['cat', 'dog']*2]
pd.MultiIndex.from_arrays(my_array, names=['First','Second'])
pd.MultiIndex.from_product
my_list1 = ['a','b']
my_list2 = ['cat','dog']
pd.MultiIndex.from_product([my_list1, my_list2], names=['First','Second'])
out:
索引的常用方法
索引的删除和交换
axis=1为对列处理,axis=0对行索引处理
方法 | 备注 |
---|---|
pd.swaplevel | 交换两个层, |
pd.reorder_levels | 写入所有层的顺序 |
pd.droplevel | 丢弃某一层的索引 |
用到的数据集
np.random.seed(0)
L1,L2,L3 = ['A','B'],['a','b'],['alpha','beta']
mul_index1 = pd.MultiIndex.from_product([L1,L2,L3], names=('Upper', 'Lower','Extra'))
L4,L5,L6 = ['C','D'],['c','d'],['cat','dog']
mul_index2 = pd.MultiIndex.from_product([L4,L5,L6], names=('Big', 'Small', 'Other'))
df_ex = pd.DataFrame(np.random.randint(-9,10,(8,8)), index=mul_index1, columns=mul_index2)
df_ex
df_ex.swaplevel(0,2,axis=1).head() # 列索引的第一层和第三层交换
out
df_ex.reorder_levels([2,0,1],axis=0).head() # 列表数字指代原来索引中的层
out
df_ex.droplevel(1,axis=1)
out
索引属性的修改
方法 | 描述 |
---|---|
rename_axis | 修改索引层的名字,常常传入字典 |
rename | 对索引值做修改,需要指明level |
map | 对索引元组提供遍历操作;多级索引的压缩 |
rename_axis
df_ex.rename_axis(index={'Upper':'Changed_row'},
columns={'Other':'Changed_Col'}).head()
out
rename
df_ex.rename(columns={'cat':'not_cat'}, level=2).head()
out
map
map是定义在Index上的方法,与前面rename方法中层的函数式用法是类似的,只不过它传入的不是层的标量值,而是直接传入索引的元组,这为用户进行跨层的修改提供了遍历。例如,可以等价地写出上面的字符串转大写的操作:
df_temp = df_ex.copy()
new_idx = df_temp.index.map(lambda x: (x[0], x[1], str.upper(x[2])))
df_temp.index = new_idx
df_temp.head()
out
索引的设置与重置
本节的表
df_new = pd.DataFrame({'A':list('aacd'), 'B':list('PQRT'), 'C':[1,2,3,4]})
df_new
out
set_index
索引的设置可以使用set_index完成,这里的主要参数是append,表示是否来保留原来的索引,直接把新设定的添加到原索引的内层
df_new.set_index('A')
out
df_new.set_index('A', append=True)
out
df_new.set_index(['A', 'B'])
out
也可以传入Series作为索引
my_index = pd.Series(list('WXYZ'), name='D')
df_new = df_new.set_index(['A', my_index])
df_new
reset_index
reset_index是set_index的逆函数,其主要参数是drop,表示是否要把去掉的索引层丢弃,而不是添加到列中。
df_new.reset_index(['D'], drop=True)
out
如果重置了所有的索引,那么pandas会直接重新生成一个默认索引:
df_new.reset_index()
out
索引的变形
用到的表
df_reindex = pd.DataFrame({"Weight":[60,70,80], "Height":[176,180,179]}, index=['1001','1003','1002'])
df_reindex
out
表中给出了员工信息,需要重新制作一张新的表,要求增加一名员工的同时去掉身高列并增加性别列
df_reindex.reindex(index=['1001','1002','1003','1004'],
columns=['Weight','Gender'])
还有一个与reindex功能类似的函数是reindex_like,其功能是仿照传入的表索引来进行被调用表索引的变形。
df_existed = pd.DataFrame(index=['1001','1002','1003','1004'], columns=['Weight','Gender'])
df_reindex.reindex_like(df_existed)
out:
习题
Ex1:公司员工数据集
现有一份公司员工数据集:
- 分别只使用query和loc选出年龄不超过四十岁且工作部门为Dairy或Bakery的男性。
df.query("(age<=40)&(gender=='M')&((department=='Diary')|(department=='Bakery'))")
- 选出员工ID号 为奇数所在行的第1、第3和倒数第2列。
df.iloc[(df.EmployeeID%2==1).values,[0,2,-2]].head()
- 按照以下步骤进行索引操作:
- 把后三列设为索引后交换内外两层
- 恢复中间层索引
- 修改外层索引名为Gender
- 用下划线合并两层行索引
- 把行索引拆分为原状态
- 修改索引名为原表名称
- 修改索引名为原表名称
- 修改索引名为原表名称
- 恢复默认索引并将列保持为原表的相对位置
df = pd.read_csv('../data/company.csv')
# 把后三列设为索引后交换内外两层
df=df.set_index(df.columns[-3:].tolist())
df=df.swaplevel(0,2,axis=0)
# 恢复中间层索引
df=df.reset_index('job_title')
# 修改外层索引名为Gender
df.rename_axis(index={'gender':'Gender'})
# 用下划线合并两层行索引
new_idx=df.index.map(lambda x: x[0]+'_'+x[1])
df=df.set_index(new_idx)
# 把行索引拆分为原状态
new_idx=df.index.map(lambda x:tuple(x.split('_')))
df=df.set_index(new_idx)
# 修改索引名为原表名称
df.index.names=('gender','department')
# 恢复默认索引并将列保持为原表的相对位置
df.reset_index(drop=False,inplace=True)
df[['EmployeeID', 'birthdate_key', 'age', 'city_name', 'department',
'job_title', 'gender']]
Ex2:巧克力数据集
现有一份关于巧克力评价的数据集:
- 把列索引名中的\n替换为空格
df.columns=df.columns.map(lambda x:x.replace('\n',' '))
- 巧克力Rating评分为1至5,每0.25分一档,请选出2.75分及以下且可可含量Cocoa Percent高于中位数的样本。
df['Cocoa Percent']=df['Cocoa Percent'].apply(lambda x:x.replace('%','')).astype(float)/100
df.query("(Rating<2.75)&(`Cocoa Percent`>`Cocoa Percent`.median())")
- 将Review Date和Company Location设为索引后,选出Review Date在2012年之后且Company Location不属于France, Canada, Amsterdam, Belgium的样本。
df=df.set_index(['Review Date','Company Location'])
idx=pd.IndexSlice
df=df.sort_index(level=0)
exclude = ['France', 'Canada', 'Amsterdam', 'Belgium']
df.loc[idx[2012:,~df.index.get_level_values(1).isin(exclude)],:]