深入浅出Pandas:利用Python进行数据处理与分析
上QQ阅读APP看书,第一时间看更新

4.5 数据选择

除了上文介绍的查看DataFrame样本数据外,还需要按照一定的条件对数据进行筛选。通过Pandas提供的方法可以模拟Excel对数据的筛选操作,也可以实现远比Excel复杂的查询操作。

本节将介绍如何选择一列、选择一行、按组合条件筛选数据等操作,让你对数据的操作得心应手,灵活地应对各种数据查询需求。表4-1给出了最为常用的数据查询方法,下面将进行详细介绍。

表4-1 Pandas常用的数据选择操作

099-1

4.5.1 选择列

以下两种方法都可以取一列数据,得到的数据类型为Series:

df['name'] # 会返回本列的Series, 下同
df.name
df.Q1
'''
0     89
1     36
2     57
3     93
4     65
      ..
95    48
96    21
97    98
98    11
99    21
Name: Q1, Length: 100, dtype: int64
'''

type(df.Q1)
# pandas.core.series.Series

这两种操作方法效果是一样的,切片([])操作比较通用,当列名为一个合法的Python变量时,可以直接使用点操作(.name)为属性去使用。如列名为1Q、my name等,则无法使用点操作,因为变量不允许以数字开头或存在空格,如果想使用可以将列名处理,如将空格替换为下划线、增加字母开头前缀,如s_1Q、my_name。

4.5.2 切片[]

我们可以像列表那样利用切片功能选择部分行的数据,但是不支持仅索引一条数据:

df[:2] # 前两行数据
df[4:10]
df[:] # 所有数据,一般不这么用
df[:10:2] # 按步长取
s[::-1] # 反转顺序
df[2] # 报错!

需要注意的是,切片的逻辑和Python列表的逻辑一样,不包括右边的索引值。如果切片里是一个列名组成的列表,则可筛选出这些列:

df[['name','Q4']]
'''
        name  Q4
0      Liver  64
1       Arry  57
2        Ack  84
3      Eorge  78
4        Oah  86
..       ...  ..
95   Gabriel  74
96   Austin7  43
97  Lincoln4  20
98       Eli  91
99       Ben  74

[100 rows x 2 columns]
'''

需要区别的是,如果只有一列,则会是一个DataFrame:

df[['name']] # 选择一列,返回DataFrame,注意与下例进行区分
df['name'] # 只有一列,返回Series

切片中支持条件表达式,可以按条件查询数据,5.1节会详细介绍。

4.5.3 按轴标签.loc

df.loc的格式是df.loc[<行表达式>, <列表达式>],如列表达式部分不传,将返回所有列,Series仅支持行表达式进行索引的部分。loc操作通过索引和列的条件筛选出数据。如果仅返回一条数据,则类型为Series(见图4-2)。

100-1

图4-2 df.loc的使用方法

以下示例为单个索引:

# 代表索引,如果是字符,需要加引号
df.loc[0] # 选择索引为0的行
df.loc[8]

# 索引为name
df.set_index('name').loc['Ben']
'''
team     E
Q1      21
Q2      43
Q3      41
Q4      74
Name: Ben, dtype: object
'''

以下示例为列表组成的索引:

df.loc[[0,5,10]] # 指定索引为0,5,10的行
'''
      name team  Q1  Q2  Q3  Q4
0    Liver    E  89  21  24  64
5   Harlie    C  24  13  87  43
10     Leo    B  17   4  33  79
'''

df.set_index('name').loc[['Eli', 'Ben']] # 两位学生,索引是name
df.loc[[False, True]*50] # 为真的列显示,隔一个显示一个

以下示例为带标签的切片(包括起始和停止):

df.loc[0:5] # 索引切片,代表0~5行,包括5
df.loc['2010':'2014'] # 如果索引是时间,可以用字符查询,第14章会介绍
df.loc[:] # 所有
# 本方法支持Series

附带列筛选,必须有行筛选。列部分的表达式可以是一个由希望筛选的表名组成的列表,也可以是一个用冒号隔开的切片形式,来表示从左到右全部包含,左侧和右侧可以分别省略,表示本侧所有列。

df.loc[0:5, ['name', 'Q2']]
'''
     name  Q2
0   Liver  21
1    Arry  37
2     Ack  60
3   Eorge  96
4     Oah  49
5  Harlie  13
'''

df.loc[0:9, ['Q1', 'Q2']] # 前10行,Q1和Q2两列
df.loc[:, ['Q1', 'Q2']] # 所有行,Q1和Q2两列
df.loc[:10, 'Q1':] # 0~10行,Q1后边的所有列
df.loc[:, :] # 所有内容

以上方法可以混用在行和列表达式,.loc中的表达式部分支持条件表达式,可以按条件查询数据,后续章节会详细介绍。

4.5.4 按数字索引.iloc

与loc[]可以使用索引和列的名称不同,利用df.iloc[<行表达式>, <列表达式>]格式可以使用数字索引(行和列的0~n索引)进行数据筛选,意味着iloc[]的两个表达式只支持数字切片形式,其他方面是相同的。

df.iloc[:3] # 前三行
s.iloc[:3] # 序列中的前三个
df.iloc[:] # 所有数据
df.iloc[2:20:3] # 步长为3
df.iloc[:3, [0,1]] # 前两列
df.iloc[:3, :] # 所有列
df.iloc[:3, :-2] # 从右往左第三列以左的所有列

以上方法可以混用在行和列表达式,.iloc中的表达式部分支持条件表达式,可以按条件查询数据,后续章节会详细介绍。

4.5.5 取具体值.at/.iat

如果需要取数据中一个具体的值,就像取平面直角坐标系中的一个点一样,可以使用.at[]来实现。.at类似于loc,仅取一个具体的值,结构为df.at[<索引>,<列名>]。如果是一个Series,可以直接值入索引取到该索引的值。

# 注:索引是字符,需要加引号
df.at[4, 'Q1'] # 65
df.set_index('name').at['Ben', 'Q1'] # 21 索引是name
df.at[0, 'name'] # 'Liver'
df.loc[0].at['name'] # 'Liver'
# 指定列的值对应其他列的值
df.set_index('name').at['Eorge', 'team'] # 'C'
df.set_index('name').team.at['Eorge'] # 'C'
# 指定列的对应索引的值
df.team.at[3] # 'C'

iat和iloc一样,仅支持数字索引:

df.iat[4, 2] # 65
df.loc[0].iat[1] # 'E'

4.5.6 获取数据.get

.get可以做类似字典的操作,如果无值,则返回默认值(下例中是0)。格式为df.get(key, default=None),如果是DataFrame,key需要传入列名,返回的是此列的Series;如果是Series,需要传入索引,返回的是一个定值:

df.get('name', 0) # 是name列
df.get('nameXXX', 0) # 0,返回默认值
s.get(3, 0) # 93,Series传索引返回具体值
df.name.get(99, 0) # 'Ben'

4.5.7 数据截取.truncate

df.truncate()可以对DataFrame和Series进行截取,可以将索引传入before和after参数,将这个区间以外的数据剔除。

df.truncate(before=2, after=4)
'''
    name team  Q1  Q2  Q3  Q4
2    Ack    A  57  60  18  84
3  Eorge    C  93  96  71  78
4    Oah    D  65  49  61  86
'''

s.truncate(before=2, after=4)
'''
0    89
1    36
2    57
3    93
4    65
Name: Q1, dtype: int64
'''

4.5.8 索引选择器

pd.IndexSlice是一个专门的索引选择器,它的使用方法类似df.loc[]切片中的方法,常用在多层索引中,以及需要指定应用范围(subset参数)的函数中,特别是在链式方法中。

df.loc[pd.IndexSlice[:, ['Q1', 'Q2']]]
# 变量化使用
idx = pd.IndexSlice
df.loc[idx[:, ['Q1', 'Q2']]]
df.loc[idx[:, 'Q1':'Q4'], :] # 多索引

还可以按条件查询创建复杂的选择器,以下是几个案例:

# 创建复杂条件选择器
selected = df.loc[(df.team=='A') & (df.Q1>90)]
idxs = pd.IndexSlice[selected.index, 'name']
# 应用选择器
df.loc[idxs]
# 选择这部分区域加样式
df.style.applymap(style_fun, subset=idxs)

4.5.9 小结

本节介绍了数据查询的几个常用方法,可以根据需求把所需要的行和列筛选出来。切片([])就像列表的索引操作一样,可以按行把数据筛选出来,如果传入一个列表,则可以按列把指定的列筛选出来。.loc[]和.iloc[]中提供了行和列两个位置,可以按行和列组合筛选出数据,不同的是.iloc[]仅支持轴上的数字索引。

.at[]及.iat[]与.loc[]系列一样,不过它们的两个位置都只接受一个索引,得出的是一个具体值。.get()是一个类似于字典的操作,可以将数据当作字典来操作,Series的键是索引,DataFrame的键是列名。