【问题标题】:How to take max/second max with tiers using dplyr?如何使用 dplyr 在层级中获取最大/秒最大值?
【发布时间】:2019-04-30 03:06:19
【问题描述】:

我有一个数据,我想从中获取以下信息。示例基于ID == 1

  1. 每个 ID 的第一个日期及其对应的结果(对于 ID == 1DATE == 1/3/2018)。如果有层级,则取最后一行 (RESULT == 110)。
  2. 每个 ID 的第二个日期及其对应的结果(对于 ID == 1DATE == 2/3/2018)。如果有层级,则取最后一行 (RESULT == 117)。
  3. 最低结果及其对应日期。如果最小值有 2 个日期,则输出第一个日期。第二个日期将是第二低结果的日期。
  4. 次低结果及其对应日期。如果最低值与最低结果不同。

数据:

df <- read.table(text = "
                ID DATE RESULT
                1 1/3/2018 110
                1 1/3/2018 120
                1 2/3/2018 115
                1 2/3/2018 117
                1 3/3/2018 100
                1 4/3/2018 100
                2 1/11/2018 110
                2 1/11/2018 120
                2 1/11/2018 108
                2 2/11/2018 115
                2 3/11/2018 80
                2 4/11/2018 70", header = TRUE, stringsAsFactors = FALSE) 

期望的输出:

df_out <- read.table(text = "
                ID FIRST_DATE FIRST_RESULT SECOND_DATE SECOND_RESULT LOWEST_DATE LOWEST_RESULT SECOND_LOWEST_DATE SECOND_LOWEST_RESULT
                1 2018-03-01 120 2018-03-02 117 2018-03-03 100 2018-03-04 100
                2 2018-11-01 108 2018-11-02 115 2018-11-04 70 2018-11-03 80", header = TRUE, stringsAsFactors = FALSE)

采取的步骤:

  1. 将问题一分为二,一是按日期排序,二是按结果排序。
  2. 第一部分使用dplyr::dense_rank,第二部分使用dplyr::row_number
  3. dplyr::full_join 获取最终数据帧。

我的代码运行良好,但我觉得它太长了。因此,我想问一下是否有人可以更简洁地写出来。

library(dplyr)
library(tidyr)

# First Portion
df_DATE <- df %>% 
  group_by(ID) %>% 
  mutate(DATE = dmy(DATE),
         RANK_DATE = dense_rank(DATE)) %>% 
  group_by(ID, RANK_DATE) %>% 
  filter(RANK_DATE %in% 1:2,
         row_number() == n()) %>% 
  ungroup() %>% 
  mutate(DATE = as.character(DATE)) %>% 
  gather(VARIABLE, VALUE, -c(ID, RANK_DATE)) %>% 
  unite(VARIABLE, VARIABLE, RANK_DATE) %>% 
  spread(VARIABLE, VALUE) %>% 
  select(ID, 
         FIRST_DATE = DATE_1, FIRST_RESULT = RESULT_1, 
         SECOND_DATE = DATE_2, SECOND_RESULT = RESULT_2)

# Second Portion
df_RESULT <- df %>%
  group_by(ID) %>% 
  mutate(DATE = dmy(DATE),
         RANK_RESULT = row_number(RESULT)) %>% 
  filter(RANK_RESULT %in% 1:2) %>% 
  mutate(DATE = as.character(DATE)) %>% 
  gather(VARIABLE, VALUE, -c(ID, RANK_RESULT)) %>% 
  unite(VARIABLE, VARIABLE, RANK_RESULT) %>% 
  spread(VARIABLE, VALUE) %>% 
  select(ID, 
         LOWEST_DATE = DATE_1, LOWEST_VALUE = RESULT_1, 
         SECOND_LOWEST_DATE = DATE_2, SECOND_LOWEST_VALUE = RESULT_2)

# Combine the 2 portions
df_out <- full_join(df_DATE, df_RESULT)

【问题讨论】:

    标签: r dplyr tidyr


    【解决方案1】:

    如果我没有错过任何事情,我们可以在一个链中完成此操作而无需任何重塑或加入

    library(dplyr)
    
    df %>%
      mutate(DATE = as.Date(DATE, "%d/%m/%Y")) %>%
      #arrange(ID, DATE) %>% #if need to be sure that data is arranged by `ID` and `DATE`
      group_by(ID) %>%
      summarise(FIRST_DATE = first(DATE), 
                FIRST_RESULT = RESULT[max(which(DATE == FIRST_DATE))], 
                SECOND_DATE = unique(DATE)[2], 
                SECOND_RESULT = RESULT[max(which(DATE == SECOND_DATE))], 
                LOWEST_DATE = DATE[which.min(RESULT)], 
                LOWEST_RESULT = RESULT[which.min(RESULT)], 
                SECOND_LOWEST_DATE = DATE[order(RESULT)[2]], 
                SECOND_LOWEST_RESULT = RESULT[order(RESULT)[2]])
    
    # A tibble: 2 x 9
    #     ID FIRST_DATE FIRST_RESULT SECOND_DATE SECOND_RESULT LOWEST_DATE LOWEST_RESULT SECOND_LOWEST_D… SECOND_LOWEST_R…
    #  <int> <date>            <int> <date>              <int> <date>              <int> <date>                      <int>
    #1     1 2018-03-01          120 2018-03-02            117 2018-03-03            100 2018-03-04                    100
    #2     2 2018-11-01          108 2018-11-02            115 2018-11-04             70 2018-11-03                     80
    

    解释一下:

    FIRST_DATE - 从DATE 中选择first

    FIRST_RESULT = RESULT[max(which(DATE == FIRST_DATE)) - 获取DATE 等于FIRST_DATE 的索引并选择max 索引以获取最后一行以防出现平局。

    SECOND_DATE = unique(DATE)[2] 获得第二个不同的DATE

    SECOND_RESULT = RESULT[max(which(DATE == SECOND_DATE))] - 获取DATE 等于SECOND_DATE 的索引并选择max 索引以获取最后一行以防出现平局。

    LOWEST_DATE = DATE[which.min(RESULT)] - 获取最低的DATEwhich.min 返回第一个最小值的索引 DATE

    LOWEST_RESULT - 获取LOWEST_DATE对应的RESULT

    SECOND_LOWEST_DATE = DATE[order(RESULT)[2]] - 使用order 我们按升序排列RESULT 并选择第二个条目。这既适用于关系,也适用于RESULT 中的不同条目。

    SECOND_LOWEST_RESULT - 获取对应的RESULT 条目。

    【讨论】:

      猜你喜欢
      • 2021-08-04
      • 2020-03-29
      • 1970-01-01
      • 2021-11-28
      • 2021-11-08
      • 2019-10-16
      • 1970-01-01
      • 2019-08-01
      • 1970-01-01
      相关资源
      最近更新 更多