【问题标题】:Calculate value based on multiple other values根据多个其他值计算值
【发布时间】:2021-08-13 09:11:39
【问题描述】:

我想基于多个 (>100) 其他变量在 R 中创建一些新变量。

我的数据集是这样的

  sub_id diag_1_ais diag_2_ais diag_3_ais diag_4_ais diag_5_ais diag_1_br diag_2_br diag_3_br diag_4_br diag_5_br
1      1          1          1          2          2          1         6         0         1         6         1
2      2          2                                3          2         5                             1         3
3      3          0          0       <NA>          4          1         0         0      <NA>         2         2
4      4         NA                     1          2          2        NA                   1         1         4
5      5         NA          4          2          3          5        NA         4         3         4         3

变量 diag_x_ais 可以取 0-6 之间的整数,而 diag_x_br 可以取 1-6 之间的整数。 我想让 6 个新变量对应于 6 个可能的 diag_x_br 值,即新变量将被称为 br_1、br_2 ... br_6。然后这些新变量应填充相应的 diag_x_ais 变量的最大值,即 如果diag_1_br、diag_2_br和diag_4_br都是3,那么br_3应该取diag_1_ais、diag_2_ais和diag_4_ais的最大值。

另请参阅下面的示例数据集:

  sub_id diag_1_ais diag_2_ais diag_3_ais diag_4_ais diag_5_ais diag_1_br diag_2_br diag_3_br diag_4_br diag_5_br br_1 br_2 br_3 br_4 br_5 br_6
1      1          1          1          2          2          1         6         0         1         6         1    2   NA   NA   NA   NA    2
2      2          2          1          4          3          5         5         2         2         1         3    3    4    5   NA    2   NA
3      3          0          0         NA          4          1         0         0        NA         2         2   NA    4   NA   NA   NA   NA
4      4         NA                     1          2          2        NA                   1         1         4    2   NA   NA    2   NA   NA
5      5         NA          4          2          3          5        NA         4         3         4         3   NA   NA    5    4   NA   NA

此后,我想要一个最终变量,它计算最多三个最大 br_x 变量的总和,示例如下所示:

  sub_id diag_1_ais diag_2_ais diag_3_ais diag_4_ais diag_5_ais diag_1_br diag_2_br diag_3_br diag_4_br diag_5_br br_1 br_2 br_3 br_4 br_5 br_6 sum3
1      1          1          1          2          2          1         6         0         1         6         1    2   NA   NA   NA   NA    2    4
2      2          2          1          4          3          5         5         2         2         1         3    3    4    5   NA    2   NA   12
3      3          0          0         NA          4          1         0         0        NA         2         2   NA    4   NA   NA   NA   NA    4
4      4         NA                     1          2          2        NA                   1         1         4    2   NA   NA    2   NA   NA    4
5      5         NA          4          2          3          5        NA         4         3         4         3   NA   NA    5    4   NA   NA    9

我的实际数据集有 60 个 diag_x_ais 变量和 60 个 diag_x_br 变量和 4000 行。

我希望有人可以帮助我在 R 中做到这一点。谢谢!

【问题讨论】:

  • diag_1_aisdiag_2_br 之间的关系以及如何计算您的br_x 有点不清楚,请您详细说明一下?
  • Ofc。当我达到字符限制时,我会将答案分成两部分。 diag_1_ais 与 diag_1_br 相关,diag_2_ais 与 diag_2_br 相关等等(这些“对”总共有 60 个)。然后我想创建六个新的 br_ 变量,从 br_1 到 br_6。 br_ 变量以 diag_x_br 可以取的值命名,即整数 1-6。如果我们从 br_1 开始,那么我希望它在所有 diag_x_br 变量(即 60 个变量)中“搜索”1,并插入相应 diag_x_ais 变量的最大值。
  • 假设 diag_3_br、diag_4_br 和 diag_7_br 都取值 1,它们对应的 diag_3_ais、diag_4_ais 和 diag_7_ais 分别取值 1、4、2。那么 br_1 应该取值 4,因为这是对应的 diag_x_ais 值的最大值。这有意义吗?
  • 我明白你的意思。

标签: r dataframe


【解决方案1】:

我认为您可以使用以下解决方案。我做了一点修改,以便我们只对前 3 个最大值求和:

library(dplyr)
library(purrr)

df %>%
  bind_cols(as.data.frame(t(map_dfr(1:6, function(a) pmap_dfc(df, ~ {x <- c(...)[grepl("br", names(df))]
  inds <- which(x == a) 
  if(length(inds) != 0) {
    y <- c(...)[grepl("ais", names(df))]
    max(y[inds])
  } else {
    NA
  }})))) %>%
    setNames(paste0("br", 1:6))) %>% 
  rowwise() %>%
  mutate(sum = sum(sort(as.numeric(c_across(starts_with("br"))), decreasing = TRUE)[1:3], na.rm = TRUE)) %>%
  select(starts_with("br"), sum)

结果输出

# A tibble: 5 x 7
# Rowwise: 
  br1   br2   br3   br4   br5   br6     sum
  <chr> <chr> <chr> <chr> <chr> <chr> <dbl>
1 2     NA    NA    NA    NA    2         4
2 3     4     5     NA    2     NA       12
3 NA    4     NA    NA    NA    NA        4
4 2     NA    NA    2     NA    NA        4
5 NA    NA    5     4     NA    NA        9

【讨论】:

  • 感谢大家在这里帮助我。我最终使用了 OneTrickDragon 的解决方案,因为它更容易理解,但我非常感谢您的帮助和所有三个答案。再次感谢!
【解决方案2】:

您可以使用一些繁重的数据。在大型数据集上转换很可能效率不高。您的数据集中有一些空值,NA0。我没有处理它们(并将空值替换为 NA 以使导入更容易)。

library(tidyr)
library(dplyr)

data %>% 
  pivot_longer(-sub_id, 
               names_to = c("name", "cat"), 
               names_pattern = ".*_(\\d+)_(.*)") %>% 
  pivot_wider(names_from = "cat") %>% 
  group_by(sub_id, br) %>% 
  summarise(value = max(ais), .groups = "drop") %>% 
  filter(br %in% 1:6) %>%
  group_by(sub_id) %>% 
  mutate(sum = sum(tail(sort(value), 3))) %>% 
  pivot_wider(names_from = br,
              names_glue = "br_{br}") %>% 
  select(sub_id, paste0("br_", 1:6), sum)

返回

# A tibble: 5 x 8
  sub_id  br_1  br_2  br_3  br_4  br_5  br_6   sum
   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1      1     2    NA    NA    NA    NA     2     4
2      2     3     4     5    NA     2    NA    12
3      3    NA     4    NA    NA    NA    NA     4
4      4     2    NA    NA     2    NA    NA     4
5      5    NA    NA     5     4    NA    NA     9

添加一个right_join(data, by = "sub_id") 为您提供示例输出(减去列的顺序)。 我从this answer 那里得到了一个想法。

数据

data <- structure(list(sub_id = c(1, 2, 3, 4, 5), diag_1_ais = c(1, 2, 
0, NA, NA), diag_2_ais = c(1, 1, 0, NA, 4), diag_3_ais = c(2, 
4, NA, 1, 2), diag_4_ais = c(2, 3, 4, 2, 3), diag_5_ais = c(1, 
5, 1, 2, 5), diag_1_br = c(6, 5, 0, NA, NA), diag_2_br = c(0, 
2, 0, NA, 4), diag_3_br = c(1, 2, NA, 1, 3), diag_4_br = c(6, 
1, 2, 1, 4), diag_5_br = c(1, 3, 2, 4, 3)), row.names = c(NA, 
-5L), class = c("tbl_df", "tbl", "data.frame"))

【讨论】:

  • 不错的解决方案。数据集之间存在一些差异,我对为什么无法获得预期结果一无所知。
  • @AnoushiravanR 我错过了“总和前 3 部分”。还在为那个苦苦挣扎。第 2 行的结果应该是 12 而不是 14
  • 终于修好了。
  • 太棒了! tail 功能非常有用。如果可以的话,我会完全放弃tidyverse,转而支持base R。
  • @Martin Gal,谢谢大家在这里帮助我。我最终使用了 OneTrickDragon 的解决方案,因为它更容易理解,但我非常感谢您的帮助和所有三个答案。再次感谢!
【解决方案3】:

第一部分:

data <- data.frame(sub_id = c(1,2,3,4,5),
                 diag_1_ais  = c(1,2,0,NA,NA),
                 diag_2_ais  = c(1,1,0,NA,4),
                 diag_3_ais  = c(2,4,NA,1,2),
                 diag_4_ais  = c(2,3,4,2,3),
                 diag_5_ais  = c(1,5,1,2,5),
                 diag_1_br = c(6,5,0,NA,NA),
                 diag_2_br = c(0,2,0,NA,4),
                 diag_3_br = c(1,2,NA,1,3),
                 diag_4_br = c(6,1,2,1,4),
                 diag_5_br = c(1,3,2,4,3))

calc_br <- function(data, value, firstBr, lastBr) {
    br <- c()
    for (i in 1:nrow(data)){
        if (length(which(data[i,c(firstBr:lastBr)] %in% value))!=0){
          br <- c(br, c(max(data[i,which(data[i,c(firstBr:lastBr)] %in% value)+1]))) 
        }
        else {
            br <- c(br, c(NA))
        }
    }
    result <- br
}

firstBr = 7
lastBr = 11

data$br_1 <- calc_br(data,1,firstBr,lastBr)
data$br_2 <- calc_br(data,2,firstBr,lastBr)
data$br_3 <- calc_br(data,3,firstBr,lastBr)
data$br_4 <- calc_br(data,4,firstBr,lastBr)
data$br_5 <- calc_br(data,5,firstBr,lastBr)
data$br_6 <- calc_br(data,6,firstBr,lastBr)

这应该会产生与您的示例相同的结果。你应该只需要交换 lastBr 和 firstBr(我猜是 62 和 122)。

对于第二部分,这应该可以解决问题:

br_sum <- c()
for (i in 1:nrow(data)){
    br_sum <- c(br_sum, sum(data[i,lastBr+tail(order(data[i,c((lastBr+1):(lastBr+6))], na.last = NA), 3)]))
}
data$br_sum <- br_sum

为了完整起见,我的结果:

  sub_id diag_1_ais diag_2_ais diag_3_ais diag_4_ais diag_5_ais diag_1_br
1      1          1          1          2          2          1         6
2      2          2          1          4          3          5         5
3      3          0          0         NA          4          1         0
4      4         NA         NA          1          2          2        NA
5      5         NA          4          2          3          5        NA
  diag_2_br diag_3_br diag_4_br diag_5_br br_1 br_2 br_3 br_4 br_5 br_6 br_sum
1         0         1         6         1    2   NA   NA   NA   NA    2      4
2         2         2         1         3    3    4    5   NA    2   NA     12
3         0        NA         2         2   NA    4   NA   NA   NA   NA      4
4        NA         1         1         4    2   NA   NA    2   NA   NA      4
5         4         3         4         3   NA   NA    5    4   NA   NA      9

【讨论】:

  • 我们只需要将br_ 变量中的前三个最大值相加。这就是为什么在第 2 行中总和应该是 12 而不是 14 :)
  • 哦,我忽略了这个要求。感谢您的评论,我会解决的!
  • 忘了说我编辑了它,它现在应该可以工作了。
  • 非常感谢!我最终使用了这个答案,因为它比其他两个答案更容易理解,但我非常感谢大家的努力。
  • 很高兴为您提供帮助,我没有过多地评论代码,但很高兴它可以理解!但请记住,我的解决方案可能比其他解决方案慢。因为循环在更大的数据集上可能需要时间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-11-04
  • 2022-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-16
  • 1970-01-01
相关资源
最近更新 更多