切片应该算是pandas的基础了,我们要增删改查数据,首先要定位到数据,切片是定位到数据的一种直观而又简单的方式。
pandas切片方式:
iloc(integer-location):通过下标或boolean数组切片数据
loc(location):通过标签或boolean数组切片数据
[ ]:方括号运算符,可以通过下标、标签或boolean数组切片数据
ix:相当于loc和iloc的综合版本,既可以按标签切片,又可以按下标切片。也就是说,ix可以识别你是想按照标签切片,还是按照下标切片,功能和iloc、loc完全重复,现在已经被弃用了,2.0已经没有这个api了。
还以下图的df为例:
1、iloc
下标是客观存在的,不光是python,对于很多其他语言一样,序列数据类型,可以通过从0开始的整数作为下标来获取序列中的值。在python中,二维切片以逗号(,)分隔,逗号左边是行,右边是列,如果没有逗号,那就是切行。
iloc切片左闭右开,和python的切片规则是一样的。
import pandas as pd
scores = [23, 88, 12], [99, 88, 100], [44, 77, 68]
df = pd.DataFrame(scores, index=['张三', '李四', '王二麻子'], columns=['语文', '数学', '英语'])
print(df.iloc[0, 0]) # 获取df的第一个数据
"""
23
"""
print(df.iloc[:, :]) # 获取一个和df完全一样的dataframe
"""
语文 数学 英语
张三 23 88 12
李四 99 88 100
王二麻子 44 77 68
"""
print(df.iloc[0, :]) # 获取第一行,返回一个Series,名字是第一行的标签名
"""
语文 23
数学 88
英语 12
Name: 张三, dtype: int64
"""
print(df.iloc[:, 0::2]) # 获取从第一列开始,下标间隔为2的列,返回一个新的dataframe
"""
语文 英语
张三 23 12
李四 99 100
王二麻子 44 68
"""
print(df.iloc[:, 0]) # 获取第一列,返回一个Series,名字是第一列的列名
"""
张三 23
李四 99
王二麻子 44
Name: 语文, dtype: int64
"""
print(df.iloc[:, [0, 2]]) # 获取第一列和第3列,返回一个新的dataframe
"""
语文 英语
张三 23 12
李四 99 100
王二麻子 44 68
"""
2、loc
标签是pandas特有的,pandas给每一行每一列都命名一个名字来作为标签,如果代码中没有指定标签名,则pandas会使用下标来作为标签。
loc切片左闭右闭。
import pandas as pd
scores = [23, 88, 12], [99, 88, 100], [44, 77, 68]
df = pd.DataFrame(scores, index=['张三', '李四', '王二麻子'], columns=['语文', '数学', '英语'])
print(df.loc['张三', "语文"]) # 获取"张三"的"语文"分数
"""
23
"""
print(df.loc[:, :]) # 获取一个和df一样的dataframe
"""
语文 数学 英语
张三 23 88 12
李四 99 88 100
王二麻子 44 77 68
"""
print(df.loc["张三", :]) # 获取"张三"的所有成绩
"""
语文 23
数学 88
英语 12
Name: 张三, dtype: int64
"""
print(df.loc[:, "语文"]) # 获取所有人的"语文"成绩
"""
张三 23
李四 99
王二麻子 44
Name: 语文, dtype: int64
"""
print(df.loc[:, ["语文", "英语"]]) # 获取所有人的"语文"和"英语"成绩
"""
语文 英语
张三 23 12
李四 99 100
王二麻子 44 68
"""
print(df.loc[:, "语文":"英语"]) # 获取df中所有人的"语文"到"英语"的所有科目的成绩
"""
语文 数学 英语
张三 23 88 12
李四 99 88 100
王二麻子 44 77 68
"""
3、[]运算符
① pandas [ ]运算符 不支持二维切片,即不能[i, j]
df = pd.DataFrame({"语文": [23, 99, 44], "数学": [88, 88, 77], "英语": [12, 100, 68]}, index=["张三", "李四", "王二麻子"])
print(df["张三", "英语"])
"""
KeyError: ('张三', '英语')
"""
② 切列只能使用标签来切,不能通过下标;切多列必须传递列表,不能用冒号(:)
df = pd.DataFrame({"语文": [23, 99, 44], "数学": [88, 88, 77], "英语": [12, 100, 68]}, index=["张三", "李四", "王二麻子"])
print(df)
"""
语文 数学 英语
张三 23 88 12
李四 99 88 100
王二麻子 44 77 68
"""
print(df[0]) # KeyError: 0 , 因为没有列名是0
print(df["语文"])
"""
张三 23
李四 99
王二麻子 44
Name: 语文, dtype: int64
"""
print(df["语文":"数学"]) # Empty DataFrame
print(df[["语文", "数学"]])
"""
语文 数学
张三 23 88
李四 99 88
王二麻子 44 77
"""
③ 切行必须且只能使用冒号(:)。确实如此,因为[ ]不支持二维切片,所以切行和切列用法不能有任何重合,不然就有歧义,无法区分是切行还是切列
df = pd.DataFrame({"语文": [23, 99, 44], "数学": [88, 88, 77], "英语": [12, 100, 68]}, index=["张三", "李四", "王二麻子"])
print(df)
"""
语文 数学 英语
张三 23 88 12
李四 99 88 100
王二麻子 44 77 68
"""
print(df["张三"]) # KeyError: '张三', 没用 : 就认为是切列,又没列名叫张三,所以报错
print(df["张三":"张三"]) # 可以用标签切行,标签切则左闭右闭
"""
语文 数学 英语
张三 23 88 12
"""
print(df[0:1]) # 也可以用下标来切行,下标切则左闭右开
"""
语文 数学 英语
张三 23 88 12
"""
print(df[:])
"""
语文 数学 英语
张三 23 88 12
李四 99 88 100
王二麻子 44 77 68
"""
其实 [ ] 运算符更像是对iloc和loc的一个补充,比如我们要取所有人的语文成绩,如果是用loc要这么做:
df.loc[:, "语文"]
这是没办法的,因为loc的规则就是优先切行,切列部分只能在逗号(,)后面,但是如果用[]就很简单了:
df["语文"]
所以说iloc、loc、[] 三种切片方式是属于侧重点各不相同,只是为了应对不同的切片条件和要求,虽然可能一个切片要求用三种方式都能实现,但是我们不应该关注他们的替代性,而是关注各自的侧重性,选出当前条件下最简便的切片方式。
Boolean数组切片
前面我们说了,不论哪种方式都可以传递一个Boolean数组来进行切片,数组的长度必须和当前所切的维度的长度一致,即切行就必须等于行数,切列就必须等于列数。True代表选中数据,False代表不选中数据。
这里要说明一下,[ ] 运算符使用Boolean数组切片只能切行,切不了列。
还是以上面的数据为例,我们现在要选出语文成绩及格的人:
print(df[[False, True, False]])
"""
语文 数学 英语
李四 99 88 100
"""
逻辑运算
在pandas中,将Series与一个数值比较,会得到一个与自身形状完全相同且全是布尔值的Series,
前面说过,切片时可以传递Boolean数组,这就是pandas切片可以使用逻辑运算的理论基础。
还是以上面例子来说,我们要筛选出语文成绩及格的人,首先我们要切出所有人的语文成绩:
df["语文"]
和数值60做判断:
df["语文"]>=60
用得到的Boolean数组来筛选数据:
df[df["语文"] >= 60]
无论多么复杂的逻辑表达式,核心原理就是这样。
1、逻辑与
pandas使用 & 来表示逻辑与。
筛选语文和数学都及格的同学:
df[(df["语文"] >= 60) & (df["数学"] >= 60)]
"""
语文 数学 英语
李四 89 80 90
王五 76 60 44
"""
2、逻辑或
pandas使用 | 来表示逻辑或。
筛选语文或者数学及格的同学:
df[(df["语文"] >= 60) | (df["数学"] >= 60)]
"""
语文 数学 英语
张三 11 99 66
李四 89 80 90
王五 76 60 44
"""
3、逻辑非
pandas使用 ~ 来表示逻辑非
筛选语文成绩不及格的同学:
df[~(df["语文"] >= 60)]
"""
语文 数学 英语
张三 11 99 66
"""
4、all() 与 any() 方法
筛选没有挂科的同学:
df[(df >= 60).all(axis=1)]
"""
语文 数学 英语
李四 89 80 90
"""
筛选至少有一科没挂科的同学:
df[(df >= 60).any(axis=1)]
"""
语文 数学 英语
张三 12 99 66
李四 89 80 90
王五 76 60 44
"""