对Pandas中的行和列多索引使用布尔索引

2024-04-28 15:21:34 发布

您现在位置:Python中文网/ 问答频道 /正文

问题以粗体结尾。但首先,让我们设置一些数据:

import numpy as np
import pandas as pd
from itertools import product

np.random.seed(1)

team_names = ['Yankees', 'Mets', 'Dodgers']
jersey_numbers = [35, 71, 84]
game_numbers = [1, 2]
observer_names = ['Bill', 'John', 'Ralph']
observation_types = ['Speed', 'Strength']

row_indices = list(product(team_names, jersey_numbers, game_numbers, observer_names, observation_types))
observation_values = np.random.randn(len(row_indices))

tns, jns, gns, ons, ots = zip(*row_indices)

data = pd.DataFrame({'team': tns, 'jersey': jns, 'game': gns, 'observer': ons, 'obstype': ots, 'value': observation_values})

data = data.set_index(['team', 'jersey', 'game', 'observer', 'obstype'])
data = data.unstack(['observer', 'obstype'])
data.columns = data.columns.droplevel(0)

这样可以得到: data

我想提取这个数据帧的一个子集用于后续分析。假设我想将jersey编号为71的行进行切片。我真的不喜欢用xs来做这件事。当您通过xs进行横截面时,您将丢失所选列。如果我跑:

^{pr2}$

然后我得到正确的行,但是我丢失了jersey列。在

xs_slice

另外,xs似乎不是一个很好的解决方案,因为我想从jersey列中得到一些不同的值。我认为一个更好的解决方案是here

data[[j in [71, 84] for t, j, g in data.index]]

boolean_slice_1

你甚至可以选择球衣和球队的组合:

data[[j in [71, 84] and t in ['Dodgers', 'Mets'] for t, j, g in data.index]]

boolean_slice_2

不错!在

所以问题是:我如何做类似的事情来选择列的子集。例如,假设我只想要代表来自Ralph的数据的列。如果不使用xs,我该怎么做呢?或者如果我只想要带有observer in ['John', 'Ralph']的列呢?再一次,我更喜欢一个保持结果中所有级别的行和列索引的解决方案……就像上面的布尔索引示例一样。在

我可以做我想做的,甚至可以合并行和列索引中的选择。但我找到的唯一解决方案是一些真正的体操:

data[[j in [71, 84] and t in ['Dodgers', 'Mets'] for t, j, g in data.index]]\
    .T[[obs in ['John', 'Ralph'] for obs, obstype in data.columns]].T

double_boolean_slice

因此,第二个问题是:有没有更简洁的方法来完成我刚才所做的?


Tags: ingamefordataindexnames解决方案team
3条回答

注意:自从Pandas v0.20以来,ix访问器已被弃用;请适当使用loc或{}。在

如果我正确地理解了这个问题,这很简单:

要得到拉尔夫的专栏:

data.ix[:,"Ralph"]

要得到其中两个的答案,请输入一个列表:

^{pr2}$

ix运算符是幂指数运算符。请记住,第一个参数是行,然后是列(与data[..][..]相反,后者正好相反)。冒号充当通配符,因此它返回axis=0中的所有行。在

一般来说,要在多索引中查找,应该传入一个元组。e、 g

data.[:,("Ralph","Speed")]

但是如果只传入一个元素,它将把它视为传入元组的第一个元素,然后传入通配符。在

比较棘手的是,如果要访问不是0级索引的列。例如,获取“速度”的所有列。那你就得多点创意了。。将index/column的get_level_values方法与布尔索引结合使用:

例如,这将在行中获取jersey 71,在列中获取strength

data.ix[data.index.get_level_values("jersey") == 71 , \
        data.columns.get_level_values("obstype") == "Strength"]

从Pandas 0.18(可能更早)开始,您可以使用pd.IndexSlice轻松地对多索引数据帧进行切片。在

对于您的特定问题,您可以使用以下选项按团队、球衣和比赛进行选择:

data.loc[pd.IndexSlice[:,[71, 84],:],:] #IndexSlice on the rows

indexlice只需要足够的级别信息,就可以去掉后面的冒号:

^{pr2}$

同样,您可以对列进行索引:

data.loc[pd.IndexSlice[:,[71, 84]],pd.IndexSlice[['John', 'Ralph']]]

这给了你问题的最后一个数据帧。在

这里有一种方法,它使用稍微更内置的感觉语法。但还是很笨重:

data.loc[
    (data.index.get_level_values('jersey').isin([71, 84])
     & data.index.get_level_values('team').isin(['Dodgers', 'Mets'])), 
    data.columns.get_level_values('observer').isin(['John', 'Ralph'])
]

所以比较一下:

^{pr2}$

结果:

1000 loops, best of 3: 395 µs per loop
1000 loops, best of 3: 409 µs per loop

comparison_of_methods

仍然希望有一个更干净或更规范的方法来做到这一点。在

相关问题 更多 >