• pandas|Task03索引


    索引

    import numpy as np
    import pandas as pd
    
    • 1
    • 2

    索引器

    表的列索引

    一般通过[]来实现,通过[列名]可以从DataFrame中取出相应的列,返回值为Series

    df=pd.read_csv('',usecols=['School', 'Grade', 'Name', 'Gender','Weight','Transfer'])
    df['Name'].head()
    #如果要取出多个列,可以通过`[列名组成的列表]`,返回值为一个DataFrame
    #从表中取出姓名和性别两列
    df[['Gender','Name']].head()
    #取出单列可以使用`.列名`取出,与`[列名]`是等价的
    df.Name.head
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2. 序列的行索引

    [a]以字符串为索引的Series
    如果取出单个索引对应元素,可以使用[item],
    若Serie只有单个值对应,则返回这个标量值,
    如果有多个值对应,则返回一个Series

    s=pd.Series([1,2,3,4,5,6],index=['a','b','a','a','a','c'])
    s['a']
    Out[8]: 
    a    1
    a    3
    a    4
    a    5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如果取出多个索引对应的元素,则可以使用[items的列表]

    #取出两个索引之间的元素,并且这两个索引是在整个索引中唯一出现,则可以使用切片
    s['c':'b':-2]
    #这里的切片包含两个端点
    
    • 1
    • 2
    • 3

    如果前后端点的值存在重复,即非唯一值,需要经过排序才能使用切片

    try:
    	s['a':'b']
    except Exception as e:
    		Err_Msg=e
    	
    Err_Msg
    s.sort_index()['a':'b']
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    [b]以整数为索引的Series
    在使用数据的读入函数的时候,如果不特别指定所对应的列作为索引,那么会生成从0开始的整数索引作为默认索引

    s=pd.Series(['a','b','c','d','e','f'],index=[1,3,1,2,5,4])
    s[1]
    s[[2,3]]
    
    • 1
    • 2
    • 3

    如果使用整数切片则会取出对应索引位置的值
    这里的切片不包含右端点

    s[1:-1:2]
    3 b
    2 d
    
    • 1
    • 2
    • 3

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

    3. loc索引器

    前面讲到了对DataFrame的列进行选取
    下面进行对行的选取
    对表而言有两种索引器

    • 基于元素的loc索引器
    • 基于位置的iloc索引器

    loc索引器一般形式是loc[*,*],第一个*表示行的选取,第二个*表示列的选取
    *的位置一共有五类合法对象:单个元素,元素列表,元素切片,布尔列表以及函数

    df_demo=df.set_index('Name')
    df_demo.head()
    
    • 1
    • 2

    [a]*为单个元素,如果该元素在索引中重复则结果为DataFrame,否则为Series

    df_demo.loc['Qiang Sun']#多个人叫这个名字返回DataFrame
    df_demo.loc['Quan Zhao']#名字唯一返回Series
    #同时选择行
    df_demo.loc['Qiang Sun','School']#返回Series
    df_demo.loc['Quan Zhao','School']#返回单个元素
    
    • 1
    • 2
    • 3
    • 4
    • 5

    [b]*为元素列表

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

    [c]*为切片

    • 如果字符串索引是唯一值的起点和终点字符则可以使用切片,并且包含两个端点,如果不唯一则报错
    df_demo.loc['Gaojuan You':'Gaoqiang Qian','School':'Gender']
    
    
    • 1
    • 2
    • 如果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]#没有返回,说明不是整数位置切片
    df_demo.loc[df_demo.Weight > 70].head()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 前面提到的传入元素列表,也可以通过isin方法返回的布尔列表等价写出
      exp:列出所有大一和大四的同学的信息
    df_demo.loc[df_demo.Grade.isin(['Freshman','Senior'])].head()
    
    • 1
    • 对于复合条件而言,可以用|(或),&(且),~(取反)的组合来实现
      exp:选出复旦大学中体重超过70kg的大四学生,北大男生中体重超过80kg的非大四的学生
    #分别求出每个条件的同学
    condition_1_1=df_demo.School=='Fudan University'
    condition_2_1=df_demo.Grade=='Senior'
    condition_3_1=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]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    【练一练】

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

    [e]*为函数
    这里的函数,必须以前面的四种合法形式之一为返回值,并且函数的输入值为DataFrame本身,假设仍然是上述复合条件筛选的例子,可以把逻辑写入一个函数中再返回,需要注意的是函数形式参数x本质上即为df_demo

    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=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
    	result=condition_1|condition_2
    	return result
    df_demo.loc[condition]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    lambda表达式

    df_demo.loc[lambda x:'Quan Zhao',lambda x:'Gender']
    #由于函数无法返回如start:end:step的切片形式,故返回切片时要用slice对象进行包装
    df_demo.loc[lambda x:slice('Gaojuan You','Gaoqiang Qian')]
    
    #series可以使用`loc`索引
    
    • 1
    • 2
    • 3
    • 4
    • 5

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

    df_chain=pd.DataFrame([[0,0],[1,0],[-1,0]],column=list('AB'))
    df_chain
    import warnings
    with warnings.catch_warnings():
    	warnings.filterwarnings('error')
    	try:
    		df_chain[df_chain.A!=0].B=1#使用方括号列索引后,再使用点的列索引
    	except Warning as w:
    		Warning_Msg=w
    print(Warning_Msg)
    
    df_chain.loc[df.chain.A!=0,'B']=1
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4. 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[1:4,2:4]
    #切片不包含结束端点
    df_demo.iloc[lambda x:slice(1,4)]
    #传入切片为返回值的函数
    #使用布尔筛选的时候应当优先考虑loc的方式
    #选出体重超过80kg的学生
    df_demo.iloc[(df_demo.Weight>80).values].head()
    df_demo.School.iloc[1]
    df_demo.School.iloc[1:5:2]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    5.query方法

    在pandas中,支持把字符串形式的查询表达式传入query方法来查询数据,其表达式的执行结果必须返回布尔列表。

    df.query('((School == "Fudan University"&'
    '(Grade == Senior)&'
    '(Weight > 70 ))|'
    '((School == "Peking University"&'
    '(Grade != "Senior")&'
    '(Weight > 80))')
    
    df.query('Weight > Weight.mean()').head()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    【NOTE】query中引用带空格的列名

    对于含有空格的列名,需要使用col name的方式进行引用

    【END】

    同时,在query中还注册了若干英语的字面用法,帮助提高可用性
    例如or , and , in ,not in
    ==等价于in
    !=等价于not in

    df.query('(Grade not in ["Freshman", "Sophomore"]) and (Gender == "Male")').head()
    
    df.query('Grade == ["Junior","Senior"]').head()
    
    • 1
    • 2
    • 3

    #对于query中的字符串,如果要引用外部变量,只需要在变量名前加@符号

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

    6. 随机抽样

    如果把DataFrame的每一行看作一个样本,或者把每一列看作一个特征,再把整个DataFrame看作总体,想要对样本或特征进行随机抽样就可以用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.sample(3,replace=True,weights=df_sample.value)
    
    • 1
    • 2

    二、多级索引

    1. 多级索引及其表的结构

    np.random.seed(0)
    multi_index = pd.MultiIndex.from_product([list('ABCD'), df.Gender.unique()], names=('School', 'Gender'))
    multi_column = pd.MultiIndex.from_product([['Height', 'Weight'], df.Grade.unique()], names=('Indicator', 'Grade'))
    df_multi = pd.DataFrame(np.c_[(np.random.randn(8,4)*5 + 163).tolist(), (np.random.randn(8,4)*5 + 65).tolist()],
                            index = multi_index, columns = multi_column).round(1)
    df_multi
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    这里的行索引和列索引都是MultiIndex类型,只不过索引中的一个元素是元组而不是单层索引中的标量。
    与单层索引类似,MultiIndex也具有名字属性
    索引的名字和值属性分别可以通过names和values获得
    如果想要得到某一层的索引,则需要通过get_level_values获得

    df_multi.index.names
    df_multi.columns.names
    df_multi.index.values
    df_multi.columns.values
    df_multi.index.get_level_values(0)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    无论是单层还是多层,用户都无法通过index_obj[0] = item的方式来修改元素,也不能通过index_name[0] = new_name的方式来修改名字

    2. 多级索引中的loc索引器

    将学校和年级设为索引,此时的行为多级索引,列为单级索引,由于默认状态的列索引不含名字,因此对应于刚刚图中IndicatorGrade的索引名位置是空缺的。

    df_multi = df.set_index(['School', 'Grade'])
    df_multi.head()
    
    • 1
    • 2

    由于多级索引中的单个元素以元组为单位,因此之前在第一节介绍的 loc 和 iloc 方法完全可以照搬,只需把标量的位置替换成对应的元组。

    当传入元组列表或单个元组或返回前二者的函数时,需要先进行索引排序以避免性能警告

    with warnings.catch_warnings():
        warnings.filterwarnings('error')
        try:
            df_multi.loc[('Fudan University', 'Junior')].head()
        except Warning as w:
            Warning_Msg = w
    Warning_Msg
    
    df_sorted = df_multi.sort_index()
    df_sorted.loc[('Fudan University', 'Junior')].head()
    
    df_sorted.loc[[('Fudan University', 'Senior'), ('Shanghai Jiao Tong University', 'Freshman')]].head()
    df_sorted.loc[df_sorted.Weight > 70].head() # 布尔列表也是可用的
    df_sorted.loc[lambda x:('Fudan University','Junior')].head()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在单级索引中只要切片端点元素是唯一的,那么就可以进行切片,但在多级索引中,无论元组在索引中是否重复出现,都必须经过排序才能使用切片,否则报错

    try:
        df_multi.loc[('Fudan University', 'Senior'):].head()
    except Exception as e:
        Err_Msg = e
    Err_Msg
    
    • 1
    • 2
    • 3
    • 4
    • 5
    df_sorted.loc[('Fudan University', 'Senior'):].head()
    df_unique = df.drop_duplicates(subset=['School','Grade']).set_index(['School', 'Grade'])
    df_unique.head()
    
    try:
        df_unique.loc[('Fudan University', 'Senior'):].head()
    except Exception as e:
        Err_Msg = e
    Err_Msg
    
    df_unique.sort_index().loc[('Fudan University', 'Senior'):].head()
    
    可以对多层的元素进行交叉组合后索引,
    但同时需要指定loc的列,全选则用:表示。
    其中,每一层需要选中的元素用列表存放,
    传入loc的形式为[(level_0_list, level_1_list), cols]#例如,想要得到所有北大和复旦的大二大三学生,可以如下写出:
    res = df_multi.loc[(['Peking University', 'Fudan University'], ['Sophomore', 'Junior']), :]
    res.head()
    #选出北大的大三学生和复旦的大二学生:
    res = df_multi.loc[[('Peking University', 'Junior'), ('Fudan University', 'Sophomore')]]
    res.head()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    3. IndexSlice对象

    即使在索引不重复的时候,也只能对元组整体进行切片,而不能对每层进行切片,也不允许将切片和布尔列表混合使用,引入IndexSlice对象就能解决这个问题。
    Slice对象一共有两种形式

    • 第一种为loc[idx[*,*]]型,
    • 第二种为loc[idx[*,*],idx[*,*]]
    np.random.seed(0)
    L1,L2 = ['A','B','C'],['a','b','c']
    mul_index1 = pd.MultiIndex.from_product([L1,L2],names=('Upper', 'Lower'))
    L3,L4 = ['D','E','F'],['d','e','f']
    mul_index2 = pd.MultiIndex.from_product([L3,L4],names=('Big', 'Small'))
    df_ex = pd.DataFrame(np.random.randint(-9,10,(9,9)), index=mul_index1, columns=mul_index2)
    df_ex
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述
    定义slice对象

    idx = pd.IndexSlice
    
    • 1

    【a】loc[idx[*,*]]
    前一个*表示行的选择,后一个*表示列的选择,与单纯的loc是类似的:

    df_ex.loc[idx['C':, ('D', 'f'):]]
    df_ex.loc[idx[:'A', lambda x:x.sum()>0]] # 列和大于0
    
    • 1
    • 2

    【b】loc[idx[*,*],idx[*,*]]

    df_ex.loc[idx[:'A', 'b':], idx['E':, 'e':]]
    #但需要注意的是,此时不支持使用函数:
    try:
        df_ex.loc[idx[:'A', lambda x: 'b'], idx['E':, 'e':]]
    except Exception as e:
        Err_Msg = e
    Err_Msg
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4. 多级索引的构造

    除了使用set_index之外,
    常用的有from_tuples, from_arrays, from_product三种方法,它们都是pd.MultiIndex对象下的函数。

    1. from_tuple
    my_tuple = [('a','cat'),('a','dog'),('b','cat'),('b','dog')]
    pd.MultiIndex.from_tuples(my_tuple, names=['First','Second'])
    
    • 1
    • 2
    1. from_arrays
      指根据传入列表中,对应层的列表进行构造:
    my_array = [list('aabb'), ['cat', 'dog']*2]
    pd.MultiIndex.from_arrays(my_array, names=['First','Second'])
    
    • 1
    • 2
    1. from_product
      指根据给定多个列表的笛卡尔积进行构造:
    my_list1 = ['a','b']
    my_list2 = ['cat','dog']
    pd.MultiIndex.from_product([my_list1, my_list2], names=['First','Second'])
    
    • 1
    • 2
    • 3

    三、索引的常用方法

    1. 索引层的交换和删除

    构造一个三级索引

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    索引层的交换由swaplevel和reorder_levels完成,前者只能交换两个层,而后者可以交换任意层

    df_ex.swaplevel(0,2,axis=1).head() # 列索引的第一层和第三层交换
    df_ex.reorder_levels([2,0,1],axis=0).head() # 列表数字指代原来索引中的层
    
    • 1
    • 2
    若想要删除某一层的索引,可以使用droplevel方法:
    df_ex.droplevel(1,axis=1)
    df_ex.droplevel([0,1],axis=0)
    
    • 1
    • 2

    2. 索引属性的修改

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

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

    如果是多级索引需要指定修改的层号level:

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

    传入参数也可以是函数,其输入值就是索引元素:

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

    3. 索引的设置与重置

    reset_indexset_index的逆函数,其主要参数是drop,表示是否要把去掉的索引层丢弃,而不是添加到列中:

    如果重置了所有的索引,那么pandas会直接重新生成一个默认索引:

    4. 索引的变形

    还有一个与reindex功能类似的函数是reindex_like,其功能是仿照传入的表索引来进行被调用表索引的变形。

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

    四、索引运算

    1. 集合的运算法则

    S A . i n t e r s e c t i o n ( S B ) = S A ∩ S B ⇔ { x ∣ x ∈ S A   a n d   x ∈ S B } \rm S_A.intersection(S_B) = \rm S_A \cap S_B \Leftrightarrow \rm \{x|x\in S_A\, and\, x\in S_B\} SA.intersection(SB)=SASB{x∣xSAandxSB}
    S A . u n i o n ( S B ) = S A ∪ S B ⇔ { x ∣ x ∈ S A   o r   x ∈ S B } \rm S_A.union(S_B) = \rm S_A \cup S_B \Leftrightarrow \rm \{x|x\in S_A\, or\, x\in S_B\} SA.union(SB)=SASB{x∣xSAorxSB}
    S A . d i f f e r e n c e ( S B ) = S A − S B ⇔ { x ∣ x ∈ S A   a n d   x ∉ S B } \rm S_A.difference(S_B) = \rm S_A - S_B \Leftrightarrow \rm \{x|x\in S_A\, and\, x\notin S_B\} SA.difference(SB)=SASB{x∣xSAandx/SB}
    S A . s y m m e t r i c _ d i f f e r e n c e ( S B ) = S A △ S B ⇔ { x ∣ x ∈ S A ∪ S B − S A ∩ S B } \rm S_A.symmetric\_difference(S_B) = \rm S_A\triangle S_B\Leftrightarrow \rm \{x|x\in S_A\cup S_B - S_A\cap S_B\} SA.symmetric_difference(SB)=SASB{x∣xSASBSASB}

    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)
    id1.union(id2)
    id1.difference(id2)
    id1.symmetric_difference(id2)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

    df_set_in_col_1[df_set_in_col_1.id1.isin(df_set_in_col_2.id2)]
    
    • 1
  • 相关阅读:
    云服务器centos8搭建网站 apache+php+mysql
    英语学习笔记14——What color‘s your ... ?
    【JS】阿拉伯数字转成中文数字(包括亿单位长数字)
    Java 嵌套循环结构与break 、continue、return 的使用
    GitHub Universe 2023:AI 技术引领软件开发创新浪潮
    在腾讯干软件测试4年,来面试要求35k,让我见识到了真正的测试届天花板...
    WebDAV之葫芦儿·派盘+纸间书摘
    docker 安装mysql、canal、redis实现redis和mysql缓存一致性
    宝塔面板 PHP fileinfo Class ‘finfo‘ not found 的解决办法
    ForkJoinPool的使用及基本原理
  • 原文地址:https://blog.csdn.net/m0_52024881/article/details/126562950