【问题标题】:How to select range of columns in a dataframe based on their name and not their indexes?如何根据名称而不是索引选择数据框中的列范围?
【发布时间】:2016-10-09 09:49:43
【问题描述】:

在这样创建的 pandas 数据框中:

import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.randint(10, size=(6, 6)),
                  columns=['c' + str(i) for i in range(6)],
                  index=["r" + str(i) for i in range(6)])

可能如下所示:

    c0  c1  c2  c3  c4  c5
r0   2   7   3   3   2   8
r1   6   9   6   7   9   1
r2   4   0   9   8   4   2
r3   9   0   4   3   5   4
r4   7   6   8   8   0   8
r5   0   6   1   8   2   2

我可以使用.loc 轻松选择某些行和/或一系列列:

print df.loc[['r1', 'r5'], 'c1':'c4']

那会返回:

    c1  c2  c3  c4
r1   9   6   7   9
r5   6   1   8   2

因此,我可以在列表中选择特定的行/列,使用冒号选择一系列行/列。

如何在 R 中做到这一点? Herehere 总是必须通过索引指定所需的列范围,但不能 - 或者至少我没有找到 - 按名称访问它们。举个例子:

df <- data.frame(c1=1:6, c2=2:7, c3=3:8, c4=4:9, c5=5:10, c6=6:11)
rownames(df) <- c('r1', 'r2', 'r3', 'r4', 'r5', 'r6')

命令

df[c('r1', 'r5'),'c1':'c4']

不起作用并引发错误。唯一对我有用的是

df[c('r1', 'r5'), 1:4]

返回

   c1 c2 c3 c4
r1  1  2  3  4
r5  5  6  7  8

但是我如何通过名称而不是索引来选择列(当我在整个分析过程中删除某些列时,这可能很重要)?在这种特殊情况下,我当然可以使用grep,但是具有任意名称的列呢?

所以我不想用

df[c('r1', 'r5'),c('c1','c2', 'c3', 'c4')]

但实际切片。

编辑:

可以在here找到后续问题。

【问题讨论】:

  • @downvoter:你能解释一下你为什么投反对票吗?这是一个带有最小可重现示例的明确问题,那么问题是什么?
  • 感觉有点像移动球门柱以专门询问有关列的问题,然后在提交答案后对其进行编辑以包含行。回滚编辑并提出一个新问题可能会更好。它们看起来非常相关,但列名和行名在 R 数据帧中的处理方式截然不同。 (虽然不是我的反对意见 - 并且不确定这是否是原因。)
  • @Gregor:好的,我对 R 的细节不太熟悉,在 Pandas 中它是直截了当的,我可以这样做:df.loc['r1':'r3', 'c1':'c4'] 所以行和列不会被区别对待。如果没有更好的结果,我当然会接受提供的答案(请参阅下面的第一条评论),因为它确实回答了原始问题。是的,你是对的,我应该将行选择放在原始问题中,所以我理解你的反对意见;谢谢你的解释!
  • 即使从一开始,我认为它作为一个单独的问题会更好(但我仍然没有反对)。我可以想到三种好的列方法:base::subset 如答案或dplyr::selectdata.table。除了 hacking 之外,我不知道行名的任何方法。但这将是一个很好的单独问题,并且可能会获得一些特定的兴趣/创新解决方案。
  • @Gregor:好的,谢谢。如前所述,我不知道行和列选择的处理方式不同,我再次编辑我的问题;感谢您让我意识到这一点。

标签: r dataframe subset code-conversion


【解决方案1】:

看来您可以使用subset 完成此操作:

> df <- data.frame(c1=1:6, c2=2:7, c3=3:8, c4=4:9, c5=5:10, c6=6:11)
> rownames(df) <- c('r1', 'r2', 'r3', 'r4', 'r5', 'r6')
> subset(df, select=c1:c4)
   c1 c2 c3 c4
r1  1  2  3  4
r2  2  3  4  5
r3  3  4  5  6
r4  4  5  6  7
r5  5  6  7  8
r6  6  7  8  9
> subset(df, select=c1:c2)
   c1 c2
r1  1  2
r2  2  3
r3  3  4
r4  4  5
r5  5  6
r6  6  7

如果您想按行名范围进行子集化,此 hack 可以:

> gRI <- function(df, rName) {which(match(rNames, rName) == 1)}
> df[gRI(df,"r2"):gRI(df,"r4"),]
   c1 c2 c3 c4 c5 c6
r2  2  3  4  5  6  7
r3  3  4  5  6  7  8
r4  4  5  6  7  8  9

【讨论】:

  • 确实有效。您现在如何同时选择行?如果你想要特定的行,那么subset(df[c('r1', 'r3'),], select=c1:c4) 可以工作,但是一系列行怎么样(见我的编辑)?现在投赞成票,以后可能会接受它,具体取决于其他答案的质量......
  • 我认为标准做法是不命名您的行,然后使用标准索引范围对行进行子集化。如果您需要行名,您可以随时将它们添加为 id 列。
  • 这可能是一个不错的解决方法。但仍然觉得奇怪,这不应该是可能的。
  • 查看我最近的编辑以获取行名称范围子集的技巧。我看到的大多数R 都是df[beginInd:endInd,] 类型行子集
  • 是的,按索引进行子集化似乎更常见,但我仍然很惊讶没有内置的。
【解决方案2】:

如果您不介意使用 data.table,subset 的另一种方法是:

data.table::setDT(df)
df[1:3, c2:c4, with=F]
   c2 c3 c4
1:  2  3  4
2:  3  4  5
3:  4  5  6

这仍然没有解决子集行范​​围的问题。

【讨论】:

  • 好的,感谢您的替代方案(赞成)。行选择不是原始问题的一部分;我没想到它与列选择有那么大的不同,所以这宁愿是一个奖励;)
【解决方案3】:

添加到@evan058 的答案:

subset(df[rownames(df) %in% c("r3", "r4", "r5"),], select=c1:c4)

c1 c2 c3 c4
r3  3  4  5  6
r4  4  5  6  7
r5  5  6  7  8

但请注意,: 运算符可能在这里不起作用;您必须写出要明确包含的每一行的名称。按其他列之一的特定值进行分组或创建索引列(如 cmets 中提到的@evan058)可能更容易。

【讨论】:

  • 谢谢,但subset(df[c('r1', 'r3'),], select=c1:c4) 似乎更方便。但我实际上想避免指定行名。无论如何都赞成;)
【解决方案4】:

使用 dplyr 包的解决方案,但您需要事先指定要选择的行

rowName2Match <- c("r1", "r5")

df1 <- df %>% 
  select(matches("2"):matches("4")) %>% 
  add_rownames() %>% 
  mutate(idRow = match(rowname, rowName2Match)) %>% 
  slice(which(!is.na(idRow))) %>% 
  select(-idRow)
df1

> df1
Source: local data frame [2 x 4]

  rowname    c2    c3    c4
   <chr> <int> <int> <int>
1      r1     2     3     4
2      r5     6     7     8

【讨论】:

  • 感谢替代解决方案,但似乎比@evan058 的解决方案复杂得多。
【解决方案5】:

这似乎太容易了,所以也许我做错了什么。

df <- data.frame(c1=1:6, c2=2:7, c3=3:8, c4=4:9, c5=5:10, c6=6:11,
                 row.names=c('r1', 'r2', 'r3', 'r4', 'r5', 'r6'))


df[c('r1','r2'),c('c1','c2')]

   c1 c2
r1  1  2
r2  2  3

【讨论】:

  • 这需要指定我想要避免的行和列。 PS:我没有投反对票
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-10
  • 1970-01-01
  • 1970-01-01
  • 2020-10-03
  • 2021-12-04
  • 2017-08-22
  • 1970-01-01
相关资源
最近更新 更多