【问题标题】:Select multiple columns by labels in pandas在熊猫中按标签选择多列
【发布时间】:2015-05-28 07:22:51
【问题描述】:

我一直在寻找通过 python 文档和论坛选择列的方法,但是关于索引列的每个示例都过于简单。

假设我有一个 10 x 10 的数据框

df = DataFrame(randn(10, 10), index=range(0,10), columns=['A', 'B', 'C', 'D','E','F','G','H','I','J'])

到目前为止,所有文档都只是一个简单的索引示例

subset = df.loc[:,'A':'C']

subset = df.loc[:,'C':]

但是当我尝试索引多个非顺序列时出现错误,像这样

subset = df.loc[:,('A':'C', 'E')]

如果我想选择列 A 到 C、E 和 G 到 I,我将如何在 Pandas 中建立索引?看来这个逻辑是行不通的

subset = df.loc[:,('A':'C', 'E', 'G':'I')]

我觉得解决方案很简单,但我无法绕过这个错误。谢谢!

【问题讨论】:

  • 你必须建立一个所有感兴趣的列的列表并像df[col_list]这样传递它,这里的问题是解析它会变得有问题,因为('A':'C')不是一个有效的元组反正
  • 这在普通索引中是不可能的:你可以给出一个切片(如'A':'C'),或者一个标签列表(如['A', 'B', 'C']),但不能同时提供两者。

标签: python pandas


【解决方案1】:

基于名称或标签(使用正则表达式语法)

df.filter(regex='[A-CEG-I]')   # does NOT depend on the column order

请注意,此处允许使用任何正则表达式,因此这种方法可以非常通用。例如。如果您希望所有列都以大写或小写“A”开头,您可以使用:df.filter(regex='^[Aa]')

基于位置(取决于列顺序)

df[ list(df.loc[:,'A':'C']) + ['E'] + list(df.loc[:,'G':'I']) ]

请注意,与基于标签的方法不同,这仅适用于您的列按字母顺序排序的情况。然而,这不一定是问题。例如,如果您的列是['A','C','B'],那么您可以将上面的'A':'C' 替换为'A':'B'

漫漫长路

为了完整起见,您始终可以选择 @Magdalena 显示的选项,即简单地单独列出每一列,尽管随着列数的增加它可能会更加冗长:

df[['A','B','C','E','G','H','I']]   # does NOT depend on the column order

上述任何方法的结果

          A         B         C         E         G         H         I
0 -0.814688 -1.060864 -0.008088  2.697203 -0.763874  1.793213 -0.019520
1  0.549824  0.269340  0.405570 -0.406695 -0.536304 -1.231051  0.058018
2  0.879230 -0.666814  1.305835  0.167621 -1.100355  0.391133  0.317467

【讨论】:

  • 请注意,在第一个解决方案中,您可以使用 df[["0, 1"],cols] 进一步选择某些行。另请注意,cols 变量中使用的“列表”技巧不适用于对行而不是列进行类似的选择。
【解决方案2】:

直接选择你想要的列....

df[['A','E','I','C']]

【讨论】:

  • 你能为 OP 多解释一下吗?
  • 不明白为什么这没有被标记为接受的答案。其他所有答案似乎都很复杂
  • 因为:试图在 DataFrame 的切片副本上设置一个值。尝试改用 .loc[row_indexer,col_indexer] = value 查看文档中的警告:pandas.pydata.org/pandas-docs/stable/…
  • 确认这个简单的解决方案仅在您希望读取而不是写入数据帧的结果子集时才有效,这将很有帮助。 OP 没有明确读取与写入的意图。
  • @code-assassin 这个答案大部分是正确的,但 OP 非常明确地要求使用快捷方法来指定 multipleranges。在许多情况下,这个答案会更加冗长。另请注意,在这种情况下,完整写出的答案并不完全如上所示,而是df[['A','B','C','E','G','H','I']]
【解决方案3】:

如何在 pandas 中按标签选择多列?

pandas 不容易支持多个基于标签的范围切片,但基于位置的切片可以,所以让我们尝试一下:

loc = df.columns.get_loc
df.iloc[:, np.r_[loc('A'):loc('C')+1, loc('E'), loc('G'):loc('I')+1]]

          A         B         C         E         G         H         I
0 -1.666330  0.321260 -1.768185 -0.034774  0.023294  0.533451 -0.241990
1  0.911498  3.408758  0.419618 -0.462590  0.739092  1.103940  0.116119
2  1.243001 -0.867370  1.058194  0.314196  0.887469  0.471137 -1.361059
3 -0.525165  0.676371  0.325831 -1.152202  0.606079  1.002880  2.032663
4  0.706609 -0.424726  0.308808  1.994626  0.626522 -0.033057  1.725315
5  0.879802 -1.961398  0.131694 -0.931951 -0.242822 -1.056038  0.550346
6  0.199072  0.969283  0.347008 -2.611489  0.282920 -0.334618  0.243583
7  1.234059  1.000687  0.863572  0.412544  0.569687 -0.684413 -0.357968
8 -0.299185  0.566009 -0.859453 -0.564557 -0.562524  0.233489 -0.039145
9  0.937637 -2.171174 -1.940916 -1.553634  0.619965 -0.664284 -0.151388

注意+1 被添加是因为使用iloc 时最右边的索引是排他的。


对其他解决方案的评论

  • filter 是 OP 标头的一种不错且简单的方法,但这可能无法很好地推广到任意列名。

  • loc 的“基于位置”的解决方案更接近理想状态,但您无法避免创建中间数据帧(最终被丢弃并被垃圾收集)来计算最终结果范围——这是我们最好避免。

  • 最后,“直接选择列”是一个不错的建议,只要您要选择的列数量很少。但是,它不适用于范围跨越数十(或可能数百)列的某些情况。

【讨论】:

  • 我认为过滤器泛化得非常好,因为它接受正则表达式,但可能不清楚,所以我只是编辑了我的答案以使其更明显。
  • 这是关于中间数据集的一个好点,但是,我不确定您的 r_ 方式明显更好。我只是对扩展至 1,000,000 行的 OP 数据进行了快速计时,我们的两种方式都比 10 行的 OP 数据慢得多。诚然,您的方式大约快 7%,但尚不清楚它是否会遇到相同的基本问题,即为更大的数据帧花费更长的时间。我确实想到,只要处理数据框的第一行,我们的任何一种方式都可以很容易地修补。
  • @JohnE 感谢 cmets。这是看待问题的另一种方式,不一定是最好的方式,但可能会根据 OP 的数据带来一些收益。
猜你喜欢
  • 2019-07-20
  • 2013-02-03
  • 2021-12-21
  • 1970-01-01
  • 2023-03-19
  • 1970-01-01
相关资源
最近更新 更多