多个条件下的子集化

Posted

技术标签:

【中文标题】多个条件下的子集化【英文标题】:Subsetting under multiple conditions 【发布时间】:2022-01-18 17:17:40 【问题描述】:

我想返回在Season Winter1 和 Winter2 中看到的Transmitter 代码的数量。答案应该是 6(在 Winter1 和 Winter2 中看到了 6 个不同的代码)。但是下面的命令返回 0:

length(unique(Dispersion[(Dispersion$Season == "Winter1") & (Dispersion$Season == "Winter2"),]$Transmitter))

什么命令适合我的问题?

structure(list(Transmitter = c("A69-1602-59814", "A69-1602-59814", 
"A69-1602-59815", "A69-1602-59815", "A69-1602-59819", "A69-1602-59820", 
"A69-1602-59821", "A69-1602-59822", "A69-1602-59823", "A69-1602-59824", 
"A69-1602-59825", "A69-1602-59826", "A69-1602-59826", "A69-1602-59827", 
"A69-1602-59828", "A69-1602-59828", "A69-1602-59830", "A69-1602-59831", 
"A69-1602-59831", "A69-1602-59832", "A69-1602-59833", "A69-1602-59834", 
"A69-1602-59835", "A69-1602-59835", "A69-1602-59836"), Batch.location = c("Lemmer", 
"Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", 
"Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", 
"Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", 
"Lemmer", "Lemmer", "Lemmer"), Location.Dispersion = c("Lemmer", 
"Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", 
"Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", 
"Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", 
"Lemmer", "Lemmer", "Lemmer"), Season = c("Winter1", "Winter2", 
"Winter1", "Winter2", "Winter1", "Winter1", "Winter1", "Winter1", 
"Winter1", "Winter1", "Winter1", "Winter1", "Winter2", "Winter1", 
"Winter1", "Winter2", "Winter1", "Winter1", "Winter2", "Winter1", 
"Winter1", "Winter1", "Winter1", "Winter2", "Winter1"), Freq = c(1961L, 
2075L, 310L, 1L, 2880L, 305L, 366L, 834L, 19L, 2580L, 564L, 997L, 
3475L, 6447L, 988L, 2991L, 355L, 3147L, 6155L, 903L, 484L, 321L, 
76L, 1921L, 3329L)), row.names = c(NA, -25L), groups = structure(list(
    Transmitter = c("A69-1602-59814", "A69-1602-59815", "A69-1602-59819", 
    "A69-1602-59820", "A69-1602-59821", "A69-1602-59822", "A69-1602-59823", 
    "A69-1602-59824", "A69-1602-59825", "A69-1602-59826", "A69-1602-59827", 
    "A69-1602-59828", "A69-1602-59830", "A69-1602-59831", "A69-1602-59832", 
    "A69-1602-59833", "A69-1602-59834", "A69-1602-59835", "A69-1602-59836"
    ), Batch.location = c("Lemmer", "Lemmer", "Lemmer", "Lemmer", 
    "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", 
    "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", 
    "Lemmer", "Lemmer", "Lemmer"), Location.Dispersion = c("Lemmer", 
    "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", 
    "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", 
    "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer", "Lemmer"
    ), .rows = structure(list(1:2, 3:4, 5L, 6L, 7L, 8L, 9L, 10L, 
        11L, 12:13, 14L, 15:16, 17L, 18:19, 20L, 21L, 22L, 23:24, 
        25L), ptype = integer(0), class = c("vctrs_list_of", 
    "vctrs_vctr", "list"))), row.names = c(NA, -19L), class = c("tbl_df", 
"tbl", "data.frame"), .drop = TRUE), class = c("grouped_df", 
"tbl_df", "tbl", "data.frame"))

【问题讨论】:

【参考方案1】:

您需要按Transmitter 分组(您的尝试中缺少)并确保两个值都在Season 的每组中。

dplyr

library(dplyr)
out <- dat %>%
  group_by(Transmitter) %>%
  filter(all(c("Winter1", "Winter2") %in% Season)) %>%
  ungroup()
out
# # A tibble: 12 x 5
#    Transmitter    Batch.location Location.Dispersion Season   Freq
#    <chr>          <chr>          <chr>               <chr>   <int>
#  1 A69-1602-59814 Lemmer         Lemmer              Winter1  1961
#  2 A69-1602-59814 Lemmer         Lemmer              Winter2  2075
#  3 A69-1602-59815 Lemmer         Lemmer              Winter1   310
#  4 A69-1602-59815 Lemmer         Lemmer              Winter2     1
#  5 A69-1602-59826 Lemmer         Lemmer              Winter1   997
#  6 A69-1602-59826 Lemmer         Lemmer              Winter2  3475
#  7 A69-1602-59828 Lemmer         Lemmer              Winter1   988
#  8 A69-1602-59828 Lemmer         Lemmer              Winter2  2991
#  9 A69-1602-59831 Lemmer         Lemmer              Winter1  3147
# 10 A69-1602-59831 Lemmer         Lemmer              Winter2  6155
# 11 A69-1602-59835 Lemmer         Lemmer              Winter1    76
# 12 A69-1602-59835 Lemmer         Lemmer              Winter2  1921

从这里您可以使用n_distinct 或其他东西来计算您需要的唯一Transmitter 值。

summarize(out, n = n_distinct(Transmitter))
# # A tibble: 1 x 1
#       n
#   <int>
# 1     6

或者只是

length(unique(out$Transmitter))
# [1] 6

基础 R,选项 1

ind <- ave(dat$Season, dat$Transmitter,
           FUN = function(z) all(c("Winter1", "Winter2") %in% z)) == "TRUE"
ind
#  [1]  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE  TRUE  TRUE FALSE  TRUE  TRUE FALSE
# [21] FALSE FALSE  TRUE  TRUE FALSE
dat[ind,]
# ...

length(unique(dat[ind, "Transmitter"]))
# [1] 6

== "TRUE" 使用字符 "TRUE" 是因为ave 强制返回值与其第一个参数相同,即dat$Season。它在内部计算logical,但之后被强制转换为字符串。 (只需运行 ave(..) 而不使用 ==... 即可查看此操作。)

基础 R,选项 2

sum(aggregate(Season ~ Transmitter, data = dat,
              FUN = function(z) all(c("Winter1", "Winter2") %in% z))$Season)
# [1] 6

【讨论】:

我相信 OP 想要 6 作为预期结果。 是的,这就是我建议n_distinct 的原因。我在这里推断,很多问题经常要求计数然后问“哪些?”,所以我想我会通过它。【参考方案2】:

split 按季节,然后使用intersectlength

with(dat, 
     do.call(\(...) intersect(...), unname(as.list(split(Transmitter, Season))))
     ) |> length()
# [1] 6

或者使用table 并计算rowSums 等于2 的行数。

with(dat, table(Transmitter, Season)) |>
  (\(x) x[rowSums(x) == length(unique(dat$Season)), ])() |>
  nrow()
# [1] 6

【讨论】:

虽然样本数据没有显示出太大的可变性,但我认为 Season 只有两个可能值的假设有点可信。 @r2evans 这很重要。我的解决方案 2 现在可能会处理。【参考方案3】:

(Dispersion$Season == "Winter1") &amp; (Dispersion$Season == "Winter2") 正在寻找 Season"Winter1""Winter2" 在同一行(同时)的行,这就是为什么这不起作用。既然您使用的是dplyr,我会这样做:

Dispersion %>%
  group_by(Transmitter) %>%
  filter(all(c("Winter1", "Winter2") %in% Season)) %>%
  ungroup() %>%
  summarize(n_trans = n_distinct(Transmitter))
# # A tibble: 1 × 1
#   n_trans
#     <int>
# 1       6

【讨论】:

【参考方案4】:

另一个base解决方案:

sum(by(dat$Season, dat$Transmitter, FUN = \(x)  all(unique(dat$Season) %in% x) ))

# [1] 6

【讨论】:

以上是关于多个条件下的子集化的主要内容,如果未能解决你的问题,请参考以下文章

通过要删除的行的多个逻辑条件子集数据帧

如何在条件满足之前用 N 行中的一些对条件行进行子集化,比我的代码更快?

如何在不使用左连接的情况下根据“OR”条件对数据框进行子集化? [复制]

如何使用每组的行数作为条件对数据框进行子集化

基于多个条件的子集数据框[重复]

r 具有多个条件的子集