pandas|Task03索引

索引

import numpy as np
import pandas as pd

索引器

表的列索引

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

df=pd.read_csv('',usecols=['School', 'Grade', 'Name', 'Gender','Weight','Transfer'])
df['Name'].head()

df[['Gender','Name']].head()

df.Name.head
  1. 序列的行索引

[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

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


s['c':'b':-2]

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

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

Err_Msg
s.sort_index()['a':'b']

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

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

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

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

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

  1. loc索引器

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

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

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

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

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

df_demo.loc['Qiang Sun']
df_demo.loc['Quan Zhao']

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

[b] * 为元素列表

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

[c] * 为切片

  • 如果字符串索引是唯一值的起点和终点字符则可以使用切片,并且包含两个端点,如果不唯一则报错
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]
df_demo.loc[df_demo.Weight > 70].head()
  • 前面提到的传入元素列表,也可以通过isin方法返回的布尔列表等价写出
    exp:列出所有大一和大四的同学的信息
df_demo.loc[df_demo.Grade.isin(['Freshman','Senior'])].head()
  • 对于复合条件而言,可以用 |(或), &(且),~(取反)的组合来实现
    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]

【练一练】

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]

lambda表达式

df_demo.loc[lambda x:'Quan Zhao',lambda x:'Gender']

df_demo.loc[lambda x:slice('Gaojuan You','Gaoqiang Qian')]

【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. 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)]

df_demo.iloc[(df_demo.Weight>80).values].head()
df_demo.School.iloc[1]
df_demo.School.iloc[1:5:2]

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

【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()

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

low,high=70,80
df.query('(Weight >= @low)&(Weight )
  1. 随机抽样

如果把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. 多级索引及其表的结构

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

pandas|Task03索引

这里的行索引和列索引都是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)

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

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

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

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

由于多级索引中的单个元素以元组为单位,因此之前在第一节介绍的 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()

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

try:
    df_multi.loc[('Fudan University', 'Senior'):].head()
except Exception as e:
    Err_Msg = e
Err_Msg
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()

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

pandas|Task03索引
定义slice对象
idx = pd.IndexSlice

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

df_ex.loc[idx['C':, ('D', 'f'):]]
df_ex.loc[idx[:'A', lambda x:x.sum()>0]]

【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

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

三、索引的常用方法

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

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

df_ex.swaplevel(0,2,axis=1).head()
df_ex.reorder_levels([2,0,1],axis=0).head()

若想要删除某一层的索引,可以使用 droplevel 方法:

df_ex.droplevel(1,axis=1)
df_ex.droplevel([0,1],axis=0)

2. 索引属性的修改

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

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

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

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

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

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

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. 集合的运算法则

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}S A ​.intersection (S B ​)=S A ​∩S B ​⇔{x∣x ∈S A ​and x ∈S B ​}
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}S A ​.union (S B ​)=S A ​∪S B ​⇔{x∣x ∈S A ​or x ∈S B ​}
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}S A ​.difference (S B ​)=S A ​−S B ​⇔{x∣x ∈S A ​and x ∈/S B ​}
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}S A ​.symmetric_difference (S B ​)=S A ​△S B ​⇔{x∣x ∈S A ​∪S B ​−S A ​∩S B ​}

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)

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

df_set_in_col_1[df_set_in_col_1.id1.isin(df_set_in_col_2.id2)]

Original: https://blog.csdn.net/m0_52024881/article/details/126562950
Author: speoki
Title: pandas|Task03索引

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/679539/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球