【问题标题】:Nested subsetting with "["带有“[”的嵌套子集
【发布时间】:2015-11-05 16:02:01
【问题描述】:

我最近发现,在使用“[”对对象(即数据框)进行子集化后,生成的对象可以在同一行代码中使用“[”进行子集化(我应该早点意识到这一点!)。这是一个例子:

# Create a data frame
df1 <- as.data.frame(matrix(1:9, nrow = 3))

# Take a look at the data frame
df1
  V1 V2 V3
1  1  4  7
2  2  5  8
3  3  6  9

# If I want the value which is on the 3rd row and 2nd column
df1[3,2]
[1] 6

# But I could also
df1[,2][3]
[1] 6

关于第二种选择的几句话。 df[,2] 返回一个原子向量,然后是 df[,2][3] 的子集。

以下数据框将有助于说明我的问题。它是一个简单的数据框,包含 26 名学生的姓名、他们各自的部门以及一个数值。为了重现性,添加了一个种子编号。

set.seed(123)
df2 <- data.frame(name = letters, dept = sample(c("econ", "stat", "math"), 26, replace = TRUE), value = runif(26, 0, 100))
head(df2)
  name dept    value
1    a econ 54.40660
2    b math 59.41420
3    c stat 28.91597
4    d math 14.71136
5    e math 96.30242
6    f econ 90.22990

我想知道econ部门中谁的价值最低。我尝试的第一件事是:

df2[df2$dept == "econ" & df2$value == min(df2$value),]
[1] name  dept  value
<0 rows> (or 0-length row.names)

我花了一段时间才明白我做错了什么,但我终于意识到问题在于我的代码假设总体价值最低的人也来自econ部门,这不是案例(这就是R 给我的答案)。实际上,总体价值最低的人来自stat部门。

i <- which(df$value == min(df$value))
df[i,]
  name dept    value
9    i stat 2.461368

当然,我可以通过以下方式轻松找到问题的答案:

df_econ <- df2[df2$dept == "econ",]
df_econ
   name dept    value
1     a econ 54.40660
6     f econ 90.22990
15    o econ 14.28000
17    q econ 41.37243
18    r econ 36.88455
19    s econ 15.24447
df_econ[df_econ$value == min(df_econ$value),]
   name dept value
15    o econ 14.28

但我想知道是否可以使用 [ 运算符的“嵌套”子集来获得相同的结果。我的意思是这样的代码:

df2[df2$dept == "econ",][... ,]

此时我不知道如何引用value 列,因为第一个子集操作df2[df2$dept == "econ",] 的结果数据框是与df2 不同的数据框。我也知道value列是第3列,但我不知道如何使用列索引而不是它们的名称来设置子集条件。

感谢您的帮助。

【问题讨论】:

  • FWIW data.tables 非常适合这种类型的操作。
  • 您需要为此进行链接,这意味着包 data.table 或包 dplyr。
  • @nrussell 感谢您的推荐。我对dplyr包比较熟悉,但是在base R中没有办法吗?

标签: r subset


【解决方案1】:

这里有一些选项:

library(dplyr) 
# also in @bramtayl's answer:
df2 %>% filter(dept == "econ") %>% filter(value==min(value))
# or
df2 %>% filter(dept == "econ") %>% slice(which.min(value))

# or...

library(data.table) 
setDT(df2)[dept == "econ"][value==min(value)]
# or
setDT(df2)[dept == "econ"][which.min(value)]

这些包提供了方便的链接方式,这些方式在基础 R 中不可用,除非很笨拙,比如

subset(subset(df2, dept=="econ"), value == min(value))

可能还有其他的包,但是这两个最近被广泛使用。


评论。如果您只是浏览数据,我建议您在 dept 级别进行聚合:

# dplyr:
df2 %>% group_by(dept) %>% slice(which.min(value))

# data.table:
df2[, .SD[which.min(value)], by=dept]


   dept name     value
1: econ    o 14.280002
2: math    t 13.880606
3: stat    i  2.461368

【讨论】:

  • 非常感谢您的回答。好吧,现在我知道这在基础 R 中是不可能的。
【解决方案2】:

同意链接是必要的:

library(magrittr)

df %>%
  `[`(.$dept == "econ", ) %>%
  `[`(.$value == min(.$value), )

为什么不坚持使用 dplyr?

library(dplyr)

df %>%
  filter(dept == "econ") %>%
  filter(value == min(value) )

【讨论】:

    猜你喜欢
    • 2017-01-31
    • 1970-01-01
    • 2015-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多