pandas学习笔记(三)
pandas学习笔记(三)
索引器
1.表的索引
通过[ ]
来实现。通过[列名]
可以从DataFrame
中取出相应的列,返回值为Series
df = pd.read_csv('./pokemon.csv')
df['name'].head()
Out[5]:
0 Bulbasaur
1 Ivysaur
2 Venusaur
3 Charmander
4 Charmeleon
Name: name, dtype: object
如果要取出多个列,则可以通过[列名组成的列表]
,其返回值为一个DataFrame
df[['name','attack']].head()
Out[6]:
name attack
0 Bulbasaur 49
1 Ivysaur 62
2 Venusaur 100
3 Charmander 52
4 Charmeleon 64
此外,若要取出单列,且列名中不包含空格,则可以用.列名
取出,这和[列名]
是等价的:
df.name.head()
Out[7]:
0 Bulbasaur
1 Ivysaur
2 Venusaur
3 Charmander
4 Charmeleon
Name: name, dtype: object
2.序列的行索引
以字符串为索引:
取出单个索引的对应元素,用[item]
;取出多个用[items的列表]
;取出某两个索引之间的元素,且这两个索引是在整个索引中唯一出现,则可以使用切片。
若Series
只有单个值对应,则返回这个标量值,如果有多个值对应,则返回一个Series
s = pd.Series([1,2,3,4,5,6],index=['a', 'b', 'a', 'a', 'a', 'c'])
s['a']
Out[9]:
a 1
a 3
a 4
a 5
dtype: int64
s['b']
Out[10]: 2
s[['c','b']]
Out[12]:
c 6
b 2
dtype: int64
s['c':'b':-2]
Out[15]:
c 6
a 4
b 2
dtype: int64
以整数为索引:
在使用数据的读入函数时,如果不特别指定所对应的列作为索引,那么会生成从0开始的整数索引作为默认索引。当然,任意一组符合长度要求的整数都可以作为索引。
和字符串一样,如果使用[int]
或[int_list]
,则可以取出对应索引元素的值:
s = pd.Series(['a', 'b', 'c', 'd', 'e', 'f'], index=[1, 3, 1, 2, 5, 4])
s[1]
Out[17]:
1 a
1 c
dtype: object
s[[2,3]]
Out[18]:
2 d
3 b
dtype: object
warning:不要把纯浮点以及任何混合类型(字符串、整数、浮点类型等的混合)作为索引,否则可能会在具体的操作时报错或者返回非预期的结果
3.loc索引器
loc索引器:
形式:一般形式是 loc[*, *]
,其中第一个*
代表行的选择
,第二个 *
代表列的选择
,如果省略第二个位置写作loc[*]
,这个*
是指行的筛选。
参数对象:
1.单个元素 2.元素列表 3.元素切片 4.布尔列表 5.函数
*
为单个元素:
直接取出相应的行或列,如果元素在索引中重复则结果为DataFrame
,否则为Series
# 只选择行
print(df_demo.loc['Qiang Sun']) # 多个人叫此名字
print(df_demo.loc['Quan Zhao']) # 名字唯一
School Grade Gender Weight Transfer
Name
Qiang Sun Tsinghua University Junior Female 53.0 N
Qiang Sun Tsinghua University Sophomore Female 40.0 N
Qiang Sun Shanghai Jiao Tong University Junior Female NaN N
School Shanghai Jiao Tong University
Grade Junior
Gender Female
Weight 53
Transfer N
Name: Quan Zhao, dtype: object
# 同时选择行和列
print(df_demo.loc['Qiang Sun', 'School') # 返回Series
print(df_demo.loc['Quan Zhao', 'School']) # 返回单个元素
Name
Qiang Sun Tsinghua University
Qiang Sun Tsinghua University
Qiang Sun Shanghai Jiao Tong University
Name: School, dtype: object
'Shanghai Jiao Tong University'
*
为元素列表:
取出列表中所有元素值对应的行或列
df_demo.loc[['Qiang Sun','Quan Zhao'], ['School','Gender']]
School Gender
Name
Qiang Sun Tsinghua University Female
Qiang Sun Tsinghua University Female
Qiang Sun Shanghai Jiao Tong University Female
Quan Zhao Shanghai Jiao Tong University Female
*
为元素切片
之前的Series
使用字符串索引时提到,如果是唯一值的起点和终点字符,那么就可以使用切片,并且包含两个端点,如果不唯一则报错
df_demo.loc['Gaojuan You':'Gaoqiang Qian', 'School':'Gender']
School Grade Gender
Name
Gaojuan You Fudan University Sophomore Male
Xiaoli Qian Tsinghua University Freshman Female
Qiang Chu Shanghai Jiao Tong University Freshman Female
Gaoqiang Qian Tsinghua University Junior Female
School Grade Gender Weight Transfer
5 Fudan University Junior Female 46.0 N
4 Tsinghua University Senior Female 50.0 N
3 Shanghai Jiao Tong University Senior Female 45.0 N
*
为布尔列表
在实际的数据处理中,根据条件来筛选行是极其常见的,此处传入loc
的布尔列表与DataFrame
长度相同,且列表为True
的位置所对应的行会被选中,False
则会被剔除。
例如,选出体重超过70kg的学生:
df_demo.loc[df_demo.Weight>70].head()
School Grade Gender Weight Transfer
Name
Mei Sun Shanghai Jiao Tong University Senior Male 89.0 N
Gaojuan You Fudan University Sophomore Male 74.0 N
Xiaopeng Zhou Shanghai Jiao Tong University Freshman Male 74.0 N
Xiaofeng Sun Tsinghua University Senior Male 71.0 N
Qiang Zheng Shanghai Jiao Tong University Senior Male 87.0 N
#注意:对于复合条件,可以用 |(或), &(且),~(取反) 的组合来实现
*
为函数
这里的函数,必须以前面的四种合法形式之一为返回值,并且函数的输入值为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 = 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_1 | condition_2]
School Grade Gender Weight Transfer
Name
Qiang Han Peking University Freshman Male 87.0 N
Chengpeng Zhou Fudan University Senior Male 81.0 N
Changpeng Zhao Peking University Freshman Male 83.0 N
Chengpeng Qian Fudan University Senior Male 73.0 Y
此外,还支持使用lambda
表达式,其返回值也同样必须是先前提到的四种形式之一
df_demo.loc[lambda x:'Quan Zhao', lambda x:'Gender']
Out[6]:'Female'
函数无法返回如start: end: step
的切片形式,故返回切片时要用 slice
对象进行包装
df_demo.loc[lambda x: slice('Gaojuan You', 'Gaoqiang Qian')]
# 结果和*参数为切片的结果一样
4.iloc索引器
iloc
的使用与loc
完全类似,只不过是针对位置进行筛选,在相应的*
位置处一共也有五类合法对象,分别是:整数、整数列表、整数切片、布尔列表以及函数,函数的返回值必须是前面的四类合法对象中的一个,其输入同样也为DataFrame
本身。
# 整数
df_demo.iloc[1, 1] # 第二行第二列
# 'Freshman'
# 整数列表
df_demo.iloc[[0, 1], [0, 1]] # 前两行前两列
'''
School Grade
Name
Gaopeng Yang Shanghai Jiao Tong University Freshman
Changqiang You Peking University Freshman
'''
# 整数切片
df_demo.iloc[1: 4, 2:4] # 切片不包含结束端点
'''
Gender Weight
Name
Changqiang You Male 70.0
Mei Sun Male 89.0
Xiaojuan Sun Female 41.0
'''
# 函数
df_demo.iloc[lambda x: slice(1, 4)] # 传入切片为返回值的函数
'''
School Grade Gender Weight Transfer
Name
Changqiang You Peking University Freshman Male 70.0 N
Mei Sun Shanghai Jiao Tong University Senior Male 89.0 N
Xiaojuan Sun Fudan University Sophomore Female 41.0 N
'''
在使用布尔列表的时候要特别注意,不能传入Series
而必须传入序列的values
,否则会报错。因此,在使用布尔筛选的时候还是应当优先考虑loc
的方式。
df_demo.iloc[(df_demo.Weight>80).values].head()
School Grade Gender Weight Transfer
Name
Mei Sun Shanghai Jiao Tong University Senior Male 89.0 N
Qiang Zheng Shanghai Jiao Tong University Senior Male 87.0 N
Qiang Han Peking University Freshman Male 87.0 N
Chengpeng Zhou Fudan University Senior Male 81.0 N
Feng Han Shanghai Jiao Tong University Sophomore Male 82.0 N
5.query方法
在pandas
中,支持把字符串形式的查询表达式传入query
方法来查询数据,其表达式的执行结果必须返回布尔列表。在进行复杂索引时,由于这种检索方式无需像普通方法一样重复使用DataFrame
的名字来引用列名,一般而言会使代码长度在不降低可读性的前提下有所减少。
将loc
一节中的复合条件查询例子可以如下改写:
df.query('((School == "Fudan University")&'
' (Grade == "Senior")&'
' (Weight > 70))|'
'((School == "Peking University")&'
' (Grade != "Senior")&'
' (Weight > 80))')
School | Grade | Name | Gender | Weight | Transfer | |
---|---|---|---|---|---|---|
38 | Peking University | Freshman | Qiang Han | Male | 87.0 | N |
66 | Fudan University | Senior | Chengpeng Zhou | Male | 81.0 | N |
99 | Peking University | Freshman | Changpeng Zhao | Male | 83.0 | N |
131 | Fudan University | Senior | Chengpeng Qian | Male | 73.0 | Y |
6.随机抽样
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]})
print(df_sample)
id | value | |
---|---|---|
0 | a | 1 |
1 | b | 2 |
2 | c | 3 |
3 | d | 4 |
4 | e | 90 |
df_sample.sample(3, replace = True, weights = df_sample.value)
id | value | |
---|---|---|
4 | e | 90 |
3 | d | 4 |
4 | e | 90 |
多级索引
1.多级索引及其表的结构
下图通过颜色区分,标记了DataFrame
的结构。与单层索引的表一样,具备元素值、行索引和列索引三个部分。其中,这里的行索引和列索引都是MultiIndex
类型,只不过索引中的一个元素是元组而不是单层索引中的标量。例如,行索引的第四个元素为("B", "Male")
,列索引的第二个元素为("Height", "Senior")
。
这里需要注意,外层连续出现相同的值时,第一次之后出现的会被隐藏显示,使结果的可读性增强。
与单层索引类似,MultiIndex
也具有名字属性,图中的School
和Gender
分别对应了表的第一层和第二层行索引的名字,Indicator
和Grade
分别对应了第一层和第二层列索引的名字。
索引的名字和值属性分别可以通过names
和values
获得:
df_multi.index.names
# FrozenList(['School', 'Gender'])
df_multi.columns.names
# FrozenList(['Indicator', 'Grade'])
df_multi.index.values
'''
array([('A', 'Female'), ('A', 'Male'), ('B', 'Female'), ('B', 'Male'),
('C', 'Female'), ('C', 'Male'), ('D', 'Female'), ('D', 'Male')],
dtype=object)
'''
df_multi.columns.values
'''
array([('Height', 'Freshman'), ('Height', 'Senior'),
('Height', 'Sophomore'), ('Height', 'Junior'),
('Weight', 'Freshman'), ('Weight', 'Senior'),
('Weight', 'Sophomore'), ('Weight', 'Junior')], dtype=object)
'''
如果想要得到某一层的索引,则需要通过get_level_values
获得:
df_multi.index.get_level_values(0)
Index(['A', 'A', 'B', 'B', 'C', 'C', 'D', 'D'], dtype='object', name='School')
但对于索引而言,无论是单层还是多层,用户都无法通过index_obj[0] = item
的方式来修改元素,也不能通过index_name[0] = new_name
的方式来修改名字
2. 多级索引中loc索引器
例:将学校和年级设为索引
df_multi = df.set_index(['School', 'Grade'])
df_multi.head()
'''
Name Gender Weight Transfer
School Grade
Shanghai Jiao Tong University Freshman Gaopeng Yang Female 46.0 N
Peking University Freshman Changqiang You Male 70.0 N
Shanghai Jiao Tong University Senior Mei Sun Male 89.0 N
Fudan University Sophomore Xiaojuan Sun Female 41.0 N
Sophomore Gaojuan You Male 74.0 N
'''
由于多级索引中的单个元素以元组为单位,因此之前在第一节介绍的loc
和iloc
方法完全可以照搬,只需把标量的位置替换成对应的元组,不过在索引前最好对MultiIndex
进行排序以避免性能警告
df_multi = df_multi.sort_index()
df_multi.loc[('Fudan University', 'Junior')].head()
'''
Name Gender Weight Transfer
School Grade
Fudan University Junior Yanli You Female 48.0 N
Junior Chunqiang Chu Male 72.0 N
Junior Changfeng Lv Male 76.0 N
Junior Yanjuan Lv Female 49.0 NaN
Junior Gaoqiang Zhou Female 43.0 N
'''
df_multi.loc[df_multi.Weight > 70].head() # 布尔列表也是可用的
'''
Name Gender Weight Transfer
School Grade
Fudan University Freshman Feng Wang Male 74.0 N
Junior Chunqiang Chu Male 72.0 N
Junior Changfeng Lv Male 76.0 N
Senior Chengpeng Zhou Male 81.0 N
Senior Chengpeng Qian Male 73.0 Y
'''
特殊用法:在多级索引中的元组有一种特殊的用法,可以对多层的元素进行交叉组合后索引,但同时需要指定 loc
的列,全选则用:
表示。其中,每一层需要选中的元素用列表存放,传入 loc
的形式为[(level_0_list, level_1_list), cols]
例:得到所有北大和复旦的大二大三学生
res = df_multi.loc[(['Peking University', 'Fudan University'],
['Sophomore', 'Junior']), :]
res.head()
'''
Name Gender Weight Transfer
School Grade
Peking University Sophomore Changmei Xu Female 43.0 N
Sophomore Xiaopeng Qin Male NaN N
Sophomore Mei Xu Female 39.0 N
Sophomore Xiaoli Zhou Female 55.0 N
Sophomore Peng Han Female 34.0 NaN
'''
res.shape
# (33, 4)
3.lndexSlice对象
前面介绍的方法,即使在索引不重复的时候,也只能对元组整体进行切片,而不能对每层进行切片,也不允许将切片和布尔列表混合使用,引入IndexSlice
对象就能解决这个问题。Slice
对象一共有两种形式,第一种为loc[idx[*,*]]
型,第二种为loc[idx[*,*],idx[*,*]]
型,下面将进行介绍。为了方便演示,下面构造一个索引不重复的DataFrame
:
loc[idx[*,*]]
型
型:这种情况并不能进行多层分别切片,前一个 *
表示行的选择,后一个 *
表示列的选择,与单纯的loc
是类似的
df_ex.loc[idx['C':, ('D', 'f'):]]
'''
Big D E F
Small f d e f d e f
Upper Lower
C a 2 5 9 -9 5 -6 3
b -5 -3 -5 6 -6 3 -5
c 6 -6 6 4 7 8 -4
'''
# 也支持布尔序列的索引
df_ex.loc[idx[:'A', lambda x:x.sum()>0]] # 列和大于0
'''
Big D F
Small d e e
Upper Lower
A a 3 6 9
b -3 3 -4
c -1 0 9
'''
loc[idx[*,*],idx[*,*]]
型
这种情况能够分层进行切片,前一个idx
指代的是行索引,后一个是列索引。
df_ex.loc[idx[:'A', 'b':], idx['E':, 'e':]]
'''
Big E F
Small e f e f
Upper Lower
A b -2 5 -4 4
c 6 6 9 -6
'''
多级索引的构造
前面提到了多级索引表的结构和切片,那么除了使用set_index
之外,如何自己构造多级索引呢?常用的有from_tuples, from_arrays, from_product
三种方法,它们都是pd.MultiIndex
对象下的函数。
from_tuples
指根据传入由元组组成的列表进行构造:
my_tuple = [('a','cat'),('a','dog'),('b','cat'),('b','dog')]
pd.MultiIndex.from_tuples(my_tuple, names=['First','Second'])
'''
MultiIndex([('a', 'cat'),
('a', 'dog'),
('b', 'cat'),
('b', 'dog')],
names=['First', 'Second'])
'''
from_arrays
指根据传入列表中,对应层的列表进行构造:
my_array = [list('aabb'), ['cat', 'dog']*2]
pd.MultiIndex.from_arrays(my_array, names=['First','Second'])
'''
MultiIndex([('a', 'cat'),
('a', 'dog'),
('b', 'cat'),
('b', 'dog')],
names=['First', 'Second'])
'''
from_product
指根据给定多个列表的笛卡尔积进行构造:
my_list1 = ['a','b']
my_list2 = ['cat','dog']
pd.MultiIndex.from_product([my_list1,
my_list2],
names=['First','Second'])
'''
MultiIndex([('a', 'cat'),
('a', 'dog'),
('b', 'cat'),
('b', 'dog')],
names=['First', 'Second'])
'''
索引的常用方法
1.索引层的交换和删除
构造的三级索引 :
索引层的交换:由 swaplevel
和reorder_levels
完成,前者只能交换两个层,而后者可以交换任意层,两者都可以指定交换的是轴是哪一个,即行索引或列索引。
df_ex.swaplevel(0,2,axis=1).head() # 列索引的第一层和第三层交换
'''
Other cat dog cat dog cat dog cat dog
Small c c d d c c d d
Big C C C C D D D D
Upper Lower Extra
A a alpha 3 6 -9 -6 -6 -2 0 9
beta -5 -3 3 -8 -3 -2 5 8
b alpha -4 4 -1 0 7 -4 6 6
beta -9 9 -6 8 5 -2 -9 -8
B a alpha 0 -9 1 -6 2 9 -7 -9
'''
df_ex.reorder_levels([2,0,1],axis=0).head() # 列表数字指代原来索引中的层
'''
Big C D
Small c d c d
Other cat dog cat dog cat dog cat dog
Extra Upper Lower
alpha A a 3 6 -9 -6 -6 -2 0 9
beta A a -5 -3 3 -8 -3 -2 5 8
alpha A b -4 4 -1 0 7 -4 6 6
beta A b -9 9 -6 8 5 -2 -9 -8
alpha B a 0 -9 1 -6 2 9 -7 -9
'''
删除某一层的索引:使用droplevel
方法
df_ex.droplevel(1,axis=1)
'''
Big C D
Other cat dog cat dog cat dog cat dog
Upper Lower Extra
A a alpha 3 6 -9 -6 -6 -2 0 9
beta -5 -3 3 -8 -3 -2 5 8
b alpha -4 4 -1 0 7 -4 6 6
beta -9 9 -6 8 5 -2 -9 -8
B a alpha 0 -9 1 -6 2 9 -7 -9
beta -9 -5 -4 -3 -1 8 6 -5
b alpha 0 1 -8 -8 -2 0 -6 -3
beta 2 5 9 -9 5 -6 3 1
'''
2.索引属性的修改
通过rename_axis
可以对索引层的名字进行修改,常用的修改方式是传入字典的映射:
df_ex.rename_axis(index={'Upper':'Changed_row'},
columns={'Other':'Changed_Col'}).head()
'''
Big C D
Small c d c d
Changed_Col cat dog cat dog cat dog cat dog
Changed_row Lower Extra
A a alpha 3 6 -9 -6 -6 -2 0 9
beta -5 -3 3 -8 -3 -2 5 8
b alpha -4 4 -1 0 7 -4 6 6
beta -9 9 -6 8 5 -2 -9 -8
B a alpha 0 -9 1 -6 2 9 -7 -9
'''
通过rename
可以对索引的值进行修改,如果是多级索引需要指定修改的层号level
:
df_ex.rename(columns={'cat':'not_cat'},
level=2).head()
'''
Big C D
Small c d c d
Other not_cat dog not_cat dog not_cat dog not_cat dog
Upper Lower Extra
A a alpha 3 6 -9 -6 -6 -2 0 9
beta -5 -3 3 -8 -3 -2 5 8
b alpha -4 4 -1 0 7 -4 6 6
beta -9 9 -6 8 5 -2 -9 -8
B a alpha 0 -9 1 -6 2 9 -7 -9
'''
传入参数也可以是函数,其输入值就是索引元素:
df_ex.rename(index=lambda x:str.upper(x),
level=2).head()
'''
Big C D
Small c d c d
Other cat dog cat dog cat dog cat dog
Upper Lower Extra
A a ALPHA 3 6 -9 -6 -6 -2 0 9
BETA -5 -3 3 -8 -3 -2 5 8
b ALPHA -4 4 -1 0 7 -4 6 6
BETA -9 9 -6 8 5 -2 -9 -8
B a ALPHA 0 -9 1 -6 2 9 -7 -9
'''