【问题标题】:How to select rows with 2 specific criteria where one criteria depends on what is the value of another如何选择具有 2 个特定条件的行,其中一个条件取决于另一个条件的值
【发布时间】:2017-11-03 21:41:20
【问题描述】:

您好,我有一个看起来像这样的数据框(实际的数据框有更多的行和更多的列,但这些是我现在特别关注的列):

     Male_ID   Mate_ID  Year  Pair_Number
  1        A         B  1987            1
  2        A         C  1987            2
  3        E         D  1988            2
  4        E         F  1990            1

我正在尝试选择包含与男性交配的第一个伴侣的 ID 的行。我想选择在给定年份内具有最低年份值和最低 Pair_Number 的行,因此我试图确保选择第一行和第三行。

我试过这段代码:

        d <- ddply(dataframe, .(Male_ID), summarise, Year = min(Year), Pair_Number = min(Pair_Number))
        results <- left_join(d, dataframe, by = c("Male_ID", "Year", "Pair_Number))

但是第一个代码给了我这个:

          Male_ID   Year   Pair_Number
       1        A   1987            1
       2        E   1988            1

第 1 行正确,但第 2 行错误。在 1988 年,男 E 的 Pair_Number 不等于 1。

我想要这个:

          Male_ID   Year  Pair_Number
       1        A   1987            1
       2        E   1988            2

谢谢!

【问题讨论】:

  • 如果我理解正确,你不也想要第 4 行吗?年份不同。
  • 不,因为我想找到雄性的第一个伴侣。第 4 行并没有给我们与雄性 E 交配过的第一个伴侣,而是给了我们他一生交配过的第二个伴侣

标签: r


【解决方案1】:

仅使用 base R
首先是数据集。

dataframe <- read.table(text = "
  Male_ID   Mate_ID  Year  Pair_Number
  1        A         B  1987            1
  2        A         C  1987            2
  3        E         D  1988            2
  4        E         F  1990            1
", header = TRUE)

现在是代码。

sp <- split(dataframe, dataframe$Male_ID)
result <- lapply(sp, function(x) x[which.min(x$Year), ])
result <- do.call(rbind, result)
row.names(result) <- NULL
rm(sp)    # tidy up
result
#  Male_ID Mate_ID Year Pair_Number
#1       A       B 1987           1
#2       E       D 1988           2

请注意,我创建了变量(类listsp 只是为了使代码更具可读性。也许你可以跳过那部分并做

result <- lapply(split(dataframe, dataframe$Male_ID), function(x)
    x[which.min(x$Year), ])

接下来是其余的代码。但我发现可读的代码是更好的代码。

【讨论】:

    【解决方案2】:

    使用dplyr 并将所有变量保留在最终结果中(如果需要,您可以将其删除):

    df <- read.table(text = "Male_ID   Mate_ID  Year  Pair_Number
    1        A         B  1987            1
    2        A         C  1987            2
    3        E         D  1988            2
    4        E         F  1990            1", header = TRUE, stringsAsFactors = FALSE)
    
    library(dplyr)
    
    df %>% 
      group_by(Male_ID) %>%
      arrange(Year, Pair_Number, .by_group = TRUE) %>%
      slice(1)
    
    #> # A tibble: 2 x 4
    #> # Groups:   Male_ID [2]
    #>   Male_ID Mate_ID  Year Pair_Number
    #>     <chr>   <chr> <int>       <int>
    #> 1       A       B  1987           1
    #> 2       E       D  1988           2
    

    【讨论】:

      【解决方案3】:

      试试:

      df %>% 
        group_by(Male_ID, Year) %>% 
        filter(Pair_Number == min(Pair_Number)) %>% 
        ungroup() %>% 
        distinct(Male_ID, .keep_all = TRUE)
      

      这给出了:

      # A tibble: 2 x 4
        Male_ID Mate_ID  Year Pair_Number
         <fctr>  <fctr> <int>       <int>
      1       A       B  1987           1
      2       E       D  1988           2
      
      1. Male_IDYear 分组
      2. 按最少Pair_Number 过滤这些组
      3. 取消组合
      4. 返回每个不同Male_ID 的第一行

      【讨论】:

      • 它似乎对我不起作用。执行此操作时,会删除 Male_ID 列。该代码也没有考虑 Year 或 Pair_Number 列,所以我不确定这是否适合我
      • 啊。 Male_ID 不应该丢失,Mate_ID 是因为那是你想要的 df 的样子。我忘了Year 和最低Pair_Number。将更新答案。
      • @JenniferDiamond 我认为它现在应该对你有用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-02-21
      • 1970-01-01
      • 2016-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-04
      相关资源
      最近更新 更多