DataWhale & Pandas(三、索引)

DataWhale & Pandas(三、索引)


Pandas学习手册


学习大纲: 


目录

DataWhale & Pandas(三、索引)

学习大纲: 

三、索引

3. 索引器

3.1 列索引

注意

 3.2 行索引

注意

3.3 loc索引器

注意

3.4.iloc

4. 多级索引

4.1 多级索引及其表的结构

4.2 多级索引中的loc索引器

注意:

5、索引的常用方法

5.1. 索引层的交换和删除

5.2 索引属性的修改

5.3. 索引的设置与重置

         5.4 索引的变形

6.索引运算

6.1. 集合的运算法则

6.2. 一般的索引运算

7.练习

Ex1:公司员工数据集

Ex2:巧克力数据集


三、索引

首先需要导入numpy和pandas库

import numpy as np

import pandas as pd

3. 索引器

在dataframe里面分为行索引和列索引。

  • 行索引:index
  • 列索引:columns

3.1 列索引

列索引呢,比较常见,一般通过[]来实现,就比方下面这个例子从数据集中取出姓名这一列:

df = pd.read_csv('../data/learn_pandas.csv', 
usecols = ['School', 'Grade', 'Name',
 'Gender', 'Weight', 'Transfer'])          #导入数据集
df['Name'].head()                          #取出姓名这列

那同理呢,取出学校这列就是:

我们学会了提取一列的方法,这个时候我们提取多列试一下,我们提取性别和姓名两列试一下:

注意:

  •   若要取出单列,且列名中不包含空格,则可以用.列名取出,这和[列名]是等价的

                                         .NAME    =      [NAME]

 3.2 行索引

以字符串为索引的Series

  • 如果取出单个索引的对应元素,则可以使用[item],若Series只有单个值对应,则返回这个标量值,如果有多个值对应,则返回一个Series
  • 如果取出多个索引的对应元素,则可以使用[items的列表]
  • 如果想要取出某两个索引之间的元素,并且这两个索引是在整个索引中唯一出现,则可以使用切片,,同时需要注意这里的切片会包含两个端点

以整数为索引的Series

  • 在使用数据的读入函数时,如果不特别指定所对应的列作为索引,那么会生成从0开始的整数索引作为默认索引。当然,任意一组符合长度要求的整数都可以作为索引。
  • 和字符串一样,如果使用[int][int_list],则可以取出对应索引元素的值
  • 如果使用整数切片,则会取出对应索引位置的值,注意这里的整数切片同Python中的切片一样不包含右端点

注意:

       不要把纯浮点以及任何混合类型(字符串、整数、浮点类型等的混合)作为索引,否则可能会在具体的操作时报错或者返回非预期的结果

3.3 loc索引器

对于表而言,有两种索引器,

  • 一种是基于元素loc索引器,
  • 另一种是基于位置iloc索引器。

loc索引器的一般形式是loc[*, *],其中:

  • 第一个*代表行的选择
  • 第二个*代表列的选择

如果省略第二个位置写作loc[*],这个*是指行的筛选。

其中,*的位置一共有五类合法对象,分别是:单个元素、元素列表、元素切片、布尔列表以及函数

这里利用set_index方法把Name列设为索引

df_demo = df.set_index('Name')
df_demo.head()

1. *为单个元素

此时,直接取出相应的行或列,如果该元素在索引中重复则结果为DataFrame,否则为Series

df_demo.loc['Qiang Sun'] # 多个人叫此名字
df_demo.loc['Quan Zhao'] # 名字唯一

也可以同时选择行和列

df_demo.loc['Qiang Sun', 'School'] # 返回Series
df_demo.loc['Quan Zhao', 'School'] # 返回单个元素

2. *为元素列表

取出列表中所有元素值对应的行或列

df_demo.loc[['Qiang Sun','Quan Zhao'], ['School','Gender']]

3. *为切片

之前的Series使用字符串索引时提到,如果是唯一值的起点和终点字符,那么就可以使用切片,并且包含两个端点,如果不唯一则报错

df_demo.loc['Gaojuan You':'Gaoqiang Qian', 'School':'Gender']

需要注意的是,如果DataFrame使用整数索引,其使用整数切片的时候和上面字符串索引的要求一致,都是元素切片,包含端点且起点、终点不允许有重复值

df_loc_slice_demo = df_demo.copy()
df_loc_slice_demo.index = range(df_demo.shape[0],0,-1)
df_loc_slice_demo.loc[5:3]

df_loc_slice_demo.loc[3:5] # 没有返回,说明不是整数位置切片

4. *为布尔列表

在实际的数据处理中,根据条件来筛选行是极其常见的,此处传入loc的布尔列表与DataFrame长度相同,且列表为True的位置所对应的行会被选中,False则会被剔除。

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

df_demo.loc[df_demo.Weight>70].head()  #选出体重超过70kg的学生
df_demo.loc[df_demo.Grade.isin(['Freshman', 'Senior'])].head()  #选出所有大一和大四的同学信息
#  选出复旦大学中体重超过70kg的大四学生,或者北大男生中体重超过80kg的非大四的学生
condition_1_1 = df_demo.School == 'Fudan University'
condition_1_2 = df_demo.Grade == 'Senior'
condition_1_3 = df_demo.Weight > 70
condition_1 = condition_1_1 & condition_1_2 & condition_1_3
condition_2_1 = df_demo.School == 'Peking University'
condition_2_2 = df_demo.Grade == 'Senior'
condition_2_3 = df_demo.Weight > 80
condition_2 = condition_2_1 & (~condition_2_2) & condition_2_3
df_demo.loc[condition_1 | condition_2] ##同时使用多个条件时可以通过定义布尔值变量进行多条件筛选

5.*为函数

这里的函数,必须以前面的四种合法形式之一为返回值,并且函数的输入值为DataFrame本身。

def condition(x):
    condition_1_1 = x.School == 'Fudan University'
    condition_1_2 = x.Grade == 'Senior'
    condition_1_3 = x.Weight > 70
    condition_1 = condition_1_1 & condition_1_2 & condition_1_3
    condition_2_1 = x.School == 'Peking University'
    condition_2_2 = x.Grade == 'Senior'
    condition_2_3 = x.Weight > 80
    condition_2 = condition_2_1 & (~condition_2_2) & condition_2_3
    result = condition_1 | condition_2
    return result
df_demo.loc[condition]  ##这里的函数返回值必须是前面要求的布尔值列表

注意:

不要使用链式赋值

在对表或者序列赋值时,应当在使用一层索引器后直接进行赋值操作,这样做是由于进行多次索引后赋值是赋在临时返回的copy副本上的,而没有真正修改元素从而报出SettingWithCopyWarning警告。

3.4.iloc

.iloc() 是基于整数的索引,利用元素在各个轴上的索引序号进行选择,序号超过范围产生IndexError,切片时允许序号超过范围。

  • 整数,类似于.loc,只使用一个维度,即对行选择,小标默认从 0 开始。例如:df.iloc[5],选择df第 6 行。
  • 整数列表或者数组,例如df.iloc[[5, 1, 7]],选择df第 6 行, 第 2 行, 第 8 行。
  • 元素为整数的切片操作,不同于.loc,则下标为 stop 的数据不被选择。如:df.iloc[0:3], 只包含 0,1,2行,不包含第 3 行。
  • 也可以使用布尔数组进行筛选,例如 df.iloc[np.array(df.A>0.5)],df.iloc[list(df.A>0.5)]。
  • 注意使用布尔数组进行筛选时,可以使用 list 或者 array,使用 Series会出错,NotImplementedError 和 ValueError,前者是 Series 的 index 与待切片 DataFrame的index 不同时报错,后置 index 相同时报错。与.loc使用布尔数组,可以使用 list, array, 也可以使用Series,使用Series时 index需要一致,否则会报 IndexError。

4. 多级索引

4.1 多级索引及其表的结构

1.隐式创建

  在构造函数中给index、colunms等多个数组实现(datafarme与series都可以)

2.显式创建pd.MultiIndex

  其中.from_arrays为参数,推荐使用简单的from_product函数 

4.2 多级索引中的loc索引器

df_m=df.set_index(['School','Grade'])

注意:

  • 索引的名字和值属性分别可以通过namesvalues获得
  • 如果想要得到某一层的索引,则需要通过get_level_values获得
  • 但对于索引而言,无论是单层还是多层,用户都无法通过index_obj[0] = item的方式来修改元素,也不能通过index_name[0] = new_name的方式来修改名字
  • 在索引前最好对MultiIndex进行排序以避免性能警告
  • 与单层索引类似,若存在重复元素,则不能使用切片,请去除重复索引后给出一个元素切片的例子

5、索引的常用方法

5.1. 索引层的交换和删除

5.2 索引属性的修改

通过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()

5.3. 索引的设置与重置

new_df= pd.DataFrame({'H':list('hello'),'W':list('World'),'S':[1,2,3,4,5]})
# 索引的设置可以使用 set_index 完成,
# 其主要参数是 append ,表示是否来保留原来的索引,直接把新设定的添加到原索引的内层
df_new.set_index('A')
df_new.set_index('A', append=True)
#可以同时指定多个列作为索引
df_new.set_index(['A', 'B'])
#如果想要添加索引的列没有出现再其中,那么可以直接在参数中传入相应的Series
my_index = pd.Series(list('WXYZA'), name='D')
new_df=new_df.set_index(['H',my_index])
df_new
# reset_index 是 set_index 的逆函数,其主要参数是 drop ,
df_new.reset_index(['D'])
# 表示是否要把去掉的索引层丢弃,而不是添加到列中
df_new.reset_index(['D'],drop=True)
#如果重置了所有的索引,那么pandas会直接重新生成一个默认索引
df_new.reset_index()

5.4 索引的变形

在某些场合下,需要对索引做一些扩充或者剔除,更具体地要求是给定一个新的索引,把原表中相应的索引对应元素填充到新索引构成的表中。

#要求增加一名员工的同时去掉身高列并增加性别列
df_reindex = pd.DataFrame({"Weight":[60,70,80], "Height":[176,180,179]}, index=['1001','1003','1002'])
df_reindex.reindex(index=['1001','1002','1003','1004'], columns=['Weight','Gender'])
#这种需求常出现在时间序列索引的时间点填充以及ID编号的扩充。另外,需要注意的是原来表中的数据和新表中会根据索引自动对其,例如原先的1002号位置在1003号之后,而新表中相反,那么reindex中会根据元素对其,与位置无关。

#还有一个与reindex功能类似的函数是reindex_like,其功能是仿照传入的表的索引来进行被调用表索引的变形。例如,现在以及存在一张表具备了目标索引的条件,那么上述功能可以如下等价地写出
df_existed = pd.DataFrame(index=['1001','1002','1003','1004'], columns=['Weight','Gender'])
df_reindex.reindex_like(df_existed)

6.索引运算

6.1. 集合的运算法则

6.2. 一般的索引运算

由于集合的元素是互异的,但是索引中可能有相同的元素,先用unique 去重后再进行运算。下面构造两张
最为简单的示例表进行演示:

df_set_1 = pd.DataFrame([[0,1],[1,2],[3,4]],index = pd.Index(['a','b','a'],name='id1'))
df_set_2 = pd.DataFrame([[4,5],[2,6],[7,1]],index = pd.Index(['b','b','c'],name='id2'))
id1, id2 = df_set_1.index.unique(), df_set_2.index.unique()
id1.intersection(id2)

Index(['b'], dtype='object')

id1.union(id2)

Index(['a', 'b', 'c'], dtype='object')

id1.difference(id2)

Index(['a'], dtype='object')

id1.symmetric_difference(id2)

Index(['a', 'c'], dtype='object')

# 上述的四类运算还可以用等价的符号表示代替如下:
id1 & id2

Index(['b'], dtype='object')

id1 | id2

Index(['a', 'b', 'c'], dtype='object')

(id1 ^ id2) & id1

Index(['a'], dtype='object')

id1 ^ id2 # ^ 符号即对称差

Index(['a', 'c'], dtype='object')

#若两张表需要做集合运算的列并没有被设置索引,一种办法是先转成索引,运算后再恢复,另一种方法是利
#用isin 函数,例如在重置索引的第一张表中选出id 列交集的所在行:
df_set_1
  0 1
id1    
a 0 1
b 1 2
a 3 4
df_set_2
  0 1
id2    
b 4 5
b 2 6
c 7 1
df_set_in_col_1 = df_set_1.reset_index()
df_set_in_col_2 = df_set_2.reset_index()
df_set_in_col_1[df_set_in_col_1.id1.isin(df_set_in_col_2.id2)]
  id1 0 1
1 b 1 2

7.练习

Ex1:公司员工数据集

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

df = pd.read_csv('data/company.csv')
df.head(3)

# 
   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

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

condition_1 = df['age'] <= 40
condition_2 = df['department'].isin(['Dairy', 'Bakery'])
condition_3 = df['gender'] == 'M'
condition = condition_1 & condition_2 & condition_3
df.loc[condition].head()

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

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

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

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

  • 把后三列设为索引后交换内外两层
df_cp = df.set_index(['department', 'job_title', 'gender'])
df_cp = df_cp.swaplevel(0, 2, axis=0)
df_cp.head()

  • 恢复中间一层
df_cp = df_cp.reset_index(['job_title'])
df_cp.head()

  • 修改外层索引名为Gender
df_cp = df_cp.rename_axis(index={'gender': 'Gender'})
df_cp.head()

  • 用下划线合并两层行索引
new_idx = df_cp.index.map(lambda x: x[0] + '_' + x[1])
df_cp.index = new_idx
df_cp.head()

  • 把行索引拆分为原状态
new_idx = df_cp.index.map(lambda x: tuple(x.split('_')))
df_cp.index = new_idx
df_cp.head()

  • 修改索引名为原表名称
df_cp = df_cp.rename_axis(index=['gender', 'department'])
df_cp.head()

  • 恢复默认索引并将列保持为原表的相对位置
df_cp = df_cp.reindex(df.columns, axis=1)
df_cp.head()

Ex2:巧克力数据集

现有一份关于巧克力评价的数据集:

df = pd.read_csv('data/company.csv')
df.head(3)
  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替换为空格。
df.columns = [' '.join(i.split('\n')) for i in df.columns]
df.head()

  • 巧克力Rating评分为1至5,每0.25分一档,请选出2.75分及以下且可可含量Cocoa Percent高于中位数的样本。
df['Cocoa Percent'] = df['Cocoa Percent'].str.strip('%').astype('float64')/100
condition_1 = df['Rating'] <= 2.75
condition_2 = df['Cocoa Percent'] >= df['Cocoa Percent'].median()
df[condition_1 & condition_2].head()

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

猜你喜欢

转载自blog.csdn.net/adminkeys/article/details/111415932