【pandas03】索引器

索引器

感谢datawhale开展的每月组队学习,教材ref: 第三章:索引

表的列索引

在这里插入图片描述

序列的行索引

在这里插入图片描述

loc索引器

在这里插入图片描述

练一练,实现 select_dtypes('number')

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

在这里插入图片描述

df_demo.loc[:,[str(df_demo[v].dtype) in {'float64', 'int64'} for v in df_demo.columns]]

思路:

  • 感觉我这样的写法有点emm,但是结果是一样的,就先这样吧。后面学完再回来看看能不能再优化一点
  • 我需要遍历dataframe的列,通过 df.col_name 或 df[‘col_name’] 获得该列series的数据类型
  • [str(df_demo[v].dtype) for v in df_demo.columns]获得每个列的数据类型组成的列表
  • 因为我们是可以在 .loc[]中使用布尔列表的,于是我们可以对上面得到的 数据类型列表 做出判断(看他们是否为 'float64''int64',用set可以比用list少一丢丢丢丢丢time complexity 😅),得到布尔列表
  • 因为.loc只传一个进去的话,默认是取行的,但是我们是要取列。那么行的选择就用:来代表 我全部都要!. 然后列的选择就放我们得到的布尔列表就好。
    在这里插入图片描述

iloc 索引器

在这里插入图片描述

loc vs iloc

  • iloc 是 index-based selection, loc 是 label-based selection
  • ilocloc 都是 先行后列
  • iloc 相较来比 loc 简单一点,因为iloc忽略掉了表的索引
  • loc 如果你有meaningful的索引,那么直接用表的索引可能更简单一些
  • iloc和python本身slice一样,前闭后开。loc前闭后闭

query方法

随机抽样

在这里插入图片描述

多级索引

练一练

与单层索引类似,若存在重复元素,则不能使用切片,请去除重复索引后给出一个元素切片的例子。

temp = df_multi[~df_multi.index.duplicated(keep='first')]

在这里插入图片描述
去重之后的dataframe要sort一下,因为直接slice会报 UnsortedIndexError 的错

temp.sort_index(ascending=True, inplace=True)
temp.loc[(slice('Peking University','Tsinghua University',2), 
         slice('Freshman','Sophomore',2)), :]

去重+sorted index之后的dataframe
在这里插入图片描述
slice之后得到的,步长都设为了2
在这里插入图片描述

索引的常用方法

索引运算

练习

Ex.1 公司员工数据集

现有一份公司员工数据集:

In [167]: df = pd.read_csv('data/company.csv')
In [168]: df.head(3)
Out[168]: 
   EmployeeID birthdate_key  age  city_name department      job_title gender
0        1318      1/3/1954   61  Vancouver  Executive            CEO      M
1        1319      1/3/1957   58  Vancouver  Executive      VP Stores      F
2        1320      1/2/1955   60  Vancouver  Executive  Legal Counsel      F

分别只使用 query 和 loc 选出年龄不超过四十岁且工作部门为 Dairy 或 Bakery 的男性。

loc

def condition(x):
   		condition_1 = x.age <= 40
   		condition_2_1 = x.department == 'Dairy'
   		condition_2_2 = x.department == 'Bakery'
   		condition_2 = condition_2_1 | condition_2_2
   		condition_3 = x.gender == 'M'
   		res = condition_1 & condition_2 & condition_3
   		return res
df.loc[condition]

在这里插入图片描述

query

df.query(
		'((department == "Dairy")&'
        '(gender == "M")&'
        '(age <= 40))|'
        
        '((department == "Bakery")&'
           '(gender == "M")&'
           '(age <= 40))'
       )

在这里插入图片描述
选出员工 ID 号 为奇数所在行的第1、第3和倒数第2列。

df.loc[df.EmployeeID%2==0].iloc[:,[0,2,-2]]

先用loc[布尔列表]取出所有工号为奇数的
然后用iloc(因为取基于位置的用iloc会比较方便)行全部都要,所以行的选择用:,然后列的选择用 整数列表 把我们想要的列放进去。
在这里插入图片描述
按照以下步骤进行索引操作

  • 把后三列设为索引后交换内外两层

    temp = df.set_index(['department','job_title','gender'])
    

    在这里插入图片描述
    交换内外两层?是指 department 和 gender位置换一下?

    temp = temp.reorder_levels(['gender','job_title','department'])
    

    df.reorder_levels([新multiindex的顺序列表] 在这里插入图片描述

  • 恢复中间一层

    temp.reset_index(level='job_title')
    

    df.reset_index()在这里插入图片描述

  • 修改外层索引名为 Gender

    df.index.set_names()

    temp.index.set_names('Gender', level=0, inplace=True)
    

    在这里插入图片描述

  • 用下划线合并两层行索引

    这可能不是最优解法吧,但是最终目的是达到的

    ind = temp.index
    

    在这里插入图片描述

    ind = pd.Index([x[0]+'_'+x[1] for x in ind.tolist()])
    

    在这里插入图片描述

    temp.index = ind
    

    在这里插入图片描述
    再重新把indx新index赋给dataframe

  • 把行索引拆分为原状态

    🤯
    重新创建一个MultiIndex object,再赋给原dataframe就好了
    df.index = pd.MultiIndex object

    temp.index = pd.MultiIndex.from_arrays([temp.index.str[:1], temp.index.str[2:]],
                                     names=('Gender','Depart'))
    

    在这里插入图片描述

  • 修改索引名为原表名称

    可以在上面那步的时候直接传入参数 names=(索引名)
    df.index.names = (new_index_names)

    temp.index.names = ('gender', 'department')
    

    在这里插入图片描述

  • 恢复默认索引并将列保持为原表的相对位置

    df.reset_index()

    #恢复默认索引
    df_final = temp.reset_index()
    # 调整dataframe列的顺序
    df_final = df_final[['EmployeeID', 'birthdate_key', 'age', 'city_name',
    								'department','job_title', 'gender']]
    

    在这里插入图片描述

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

把列索引名中的 \n 替换为空格。

x.replace(‘被替换str’, ‘新str’)

choco_df.columns = [x.replace('\n', ' ') for x in choco_df.columns]

在这里插入图片描述

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

rating <= 2.75 && cocoa percent > median
通过 choco_df.info() 我们可以发现 Cocoa Percent那列的 数据类型是 object,所以我们不能对它直接使用 统计函数,我们需要先把它的数据类型转换成float

choco_df['Cocoa Percent'] = choco_df['Cocoa Percent'].str.rstrip('%').astype('float') / 100.0

在这里插入图片描述
然后

cocoa_meidan = choco_df['Cocoa Percent'].median()
choco_df.loc[(choco_df['Rating'] <= 2.75)
	            &
	         (choco_df['Cocoa Percent']>cocoa_meidan)]

在这里插入图片描述

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

choco_df_2 = choco_df.set_index(['Review Date', 'Company Location'])
choco_df_2 = choco_df_2.sort_index()

mask = ((choco_df_2.index.get_level_values(1) == 'Frence')
       	 |(choco_df_2.index.get_level_values(1) == 'Canada')
      	 |(choco_df_2.index.get_level_values(1) == 'Amsterdam')
     	 |(choco_df_2.index.get_level_values(1) == 'Belgium'))
choco_df_2[~mask].loc[idx[2012:]]

首先将Review Date 和 Company Location设为索引,为避免性能警告
在这里插入图片描述
😣 尝试了好几次两个条件一起loc,都没能成功.
但是可以先把满足 Company Location条件的 过滤出来,再去slice Review Date在2012 之后的(这里我理解的是包含2012)。
在这里插入图片描述

😯 哦… 我看到了
在这里插入图片描述
再试一下

idx = pd.IndexSlice
choco_df_2.loc[idx[2012:,                  
              ~choco_df_2.index.get_level_values(1).isin(['France','Canada','Amsterdam','Belgium'])
                   ],
              :]

在这里插入图片描述
哦猴… 结果居然shape不一样…

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值