熊猫:按部分键列表选择多行

时间:2017-09-21 14:12:36

标签: python pandas select indexing multi-index

我有一个包含多列(即分层)索引的表,如下所示:

a = pd.DataFrame([
    ['a', 'x0', 'v', 1], 
    ['a', 'x1', 'w', 2], 
    ['b', 'x0', 'y', 3], 
    ['b', 'x1', 'z', 4], 
], columns = ['key1', 'key2', 'key3', 'val']).set_index(['key1', 'key2', 'key3'])

现在,我可以选择一个完整键列表,如下所示:

a.loc[[('a', 'x0', 'v'), ('b', 'x1', 'z')]]

返回预期结果,即具有两行(值1和4)的数据帧。

然而,当我尝试使用部分键时,如下所示:

a.loc[[('a', 'x0'), ('b', 'x1')]]

然后我得到正确的键,但val列显示所有NaN值。这里有什么问题?

同样,我可以选择第一级的几个键:

a.loc[['a', 'b']]

效果很好。当我尝试那些元组时:

a.loc[[('a',), ('b',)]]

然后我再次获得NaN值。

编辑:我希望从我输入的组合键开始输出,而不是切片,即使用:

a.loc[[('a', 'x0'), ('b', 'x1')]]

我想要这个输出:

                val
key1 key2 key3     
a    x0   v       1
b    x1   z       4

但我得到的是:

                val
key1 key2 key3     
a    x0   v       NaN
b    x1   z       NaN

所以,显然,选择了正确的指数,但为什么我没有得到任何价值?

3 个答案:

答案 0 :(得分:0)

我到目前为止找到的唯一可能是:

pd.concat([a.loc[key] for key in [
    ('a', 'x0'), ('b', 'x1')
]], axis=0)

它看起来不是最佳的并且有点慢,但至少我得到了正确的结果。因此,如果您有更好的解决方案,请发布。

答案 1 :(得分:0)

问题是import numpy as np a=np.array([[1,2,3],[4,5,6]]) a=a.reshape((a.shape[0])*(a.shape[1])) # n is the nth largest taken by us print(a[np.argsort()[-n]]) 无法执行部分键的组合。如果您尝试使用多个值,它将连接包含任何值的所有行。因此,.loc()(或在此特定情况下得出相同结果的a.loc[['a','b'], :, :])可以运行并返回a.loc[['a','b']]key1'a'的所有行

但是,尝试为不同的键使用不同的值会导致一个或所有值,以便'b'返回a.loc[['a','b'], ['x0', 'x1']] key1'a'的所有组合'b'key2'x0'。当您尝试在元组中使用不完整的组合时,'x1'会假定a.loc[[('a', 'x0'), ('b', 'x1')]]('a', 'x0')为完整键。但这些(当然)不存在,因此('b', 'x1')(不可用)作为输出返回。

因此,要选择多个部分键,您将注定使用另一种方法。一种方法是按照您的建议方式进行,通过逐个尝试部分键然后连接结果。另一种方法是使用NaN来查找您感兴趣的项目。但是,这有点复杂,因为它需要一个函数,使用正确的键为行返回.select()

它的可能实现是:

True

这当然可以以更密集的方式实现,其中所有内容都合并为一行,但这会非常混乱:

sel_a_x0 = lambda row: row[0] == 'a' and row[1] == 'x0'
sel_b_x1 = lambda row: row[0] == 'b' and row[1] == 'x1'
sel_combined = lambda row: sel_a_x0(row) or sel_b_x1(row)
a.select(sel_combined)

所以我宁愿保持子表达式分开。

另外,我没有将这种方法与你自己建议的方法进行对比或比较,所以我不知道它是否更快。

答案 2 :(得分:0)

您可以先按droplevelreset_index删除所有不必要的级别,然后与isin进行比较,以获取布尔值掩码:

idx = [('a', 'x0'), ('b', 'x1')]

mask = a.index.droplevel(2).isin(idx)
mask = a.reset_index(level=2, drop=True).index.isin(idx)

print (mask)
[ True False False  True]

最后按boolean indexing过滤:

df = a[mask]
print (df)
                val
key1 key2 key3     
a    x0   v       1
b    x1   z       4