我对Python和pandas相对较新,并且正在努力处理(分层)索引。我已经涵盖了基础知识,但迷失了更高级的切片和横截面。
例如,使用以下数据帧
import pandas as pd
import numpy as np
data = pd.DataFrame(np.arange(9).reshape((3, 3)),
index=pd.Index(['Ohio', 'Colorado', 'New York'], name='state'), columns=pd.Index(['one', 'two', 'three'], name='number'))
我想选择除索引为"科罗拉多"的行之外的所有内容。对于一个小数据集,我可以做:
data.ix[['Ohio','New York']]
但是,如果唯一索引值的数量很大,那是不切实际的。天真地,我希望这样的语法
data.ix[['state' != 'Colorado']]
但是,这仅返回第一条记录"俄亥俄州",而不返回"纽约"。这有效,但很麻烦
filter = list(set(data.index.get_level_values(0).unique()) - set(['Colorado']))
data[filter]
肯定有一种更 Pythonic、更冗长的方法吗?
Python问题,而不是一个pandas
的问题:'state' != 'Colorado'
是真的,所以pandas
得到的是data.ix[[True]]
。
你可以做
>>> data.loc[data.index != "Colorado"]
number one two three
state
Ohio 0 1 2
New York 6 7 8
[2 rows x 3 columns]
或使用DataFrame.query
:
>>> data.query("state != 'New York'")
number one two three
state
Ohio 0 1 2
Colorado 3 4 5
[2 rows x 3 columns]
如果您不喜欢重复data
. (引用传递给.query()
方法的表达式是解决以下事实的唯一方法之一,否则Python会在pandas
看到它之前评估比较。
这是一个强大的解决方案,也适用于 MultiIndex 对象
单一索引
excluded = ['Ohio']
indices = data.index.get_level_values('state').difference(excluded)
indx = pd.IndexSlice[indices.values]
输出
In [77]: data.loc[indx]
Out[77]:
number one two three
state
Colorado 3 4 5
New York 6 7 8
多索引扩展
在这里,我扩展到一个多索引示例...
data = pd.DataFrame(np.arange(18).reshape(6,3), index=pd.MultiIndex(levels=[[u'AU', u'UK'], [u'Derby', u'Kensington', u'Newcastle', u'Sydney']], labels=[[0, 0, 0, 1, 1, 1], [0, 2, 3, 0, 1, 2]], names=[u'country', u'town']), columns=pd.Index(['one', 'two', 'three'], name='number'))
假设我们想从这个新的 MultiIndex 的两个示例中排除'Newcastle'
excluded = ['Newcastle']
indices = data.index.get_level_values('town').difference(excluded)
indx = pd.IndexSlice[:, indices.values]
这给出了预期的结果
In [115]: data.loc[indx, :]
Out[115]:
number one two three
country town
AU Derby 0 1 2
Sydney 3 4 5
UK Derby 0 1 2
Kensington 3 4 5
常见陷阱
- 确保索引的所有级别都已排序,您需要
data.sort_index(inplace=True)
- 确保包含列的空切片
data.loc[indx, :]
- 有时
indx = pd.IndexSlice[:, indices]
就足够了,但我发现我经常需要使用indx = pd.IndexSlice[:, indices.values]