【问题标题】:How to assign a value in a data frame based on multiple conditions of another data frame如何根据另一个数据帧的多个条件在一个数据帧中赋值
【发布时间】:2023-03-27 11:33:01
【问题描述】:

我有两个数据框,一个由称为“esame”的数值组成:

         media    id_poll fin
1   5.330000e+00     360   1
2   6.833333e-02     361   0
3   0.000000e+00     362   0
4             NA     363   0
5   8.200000e-01     364   0
6   3.416667e-01     365   0
7   0.000000e+00     366   0
8   0.000000e+00     367   0
9   0.000000e+00     368   0
10            NA     369   0
11  6.150000e-01     370   0
12  0.000000e+00     371   0
13  0.000000e+00     372   0
14            NA     373   0
15  0.000000e+00     374   0
16  0.000000e+00     375   0
17  0.000000e+00     376   0
18  1.298333e+00     377   0

第二个由数字范围组成,我想用它来检查第一个 data.frame 的“媒体”字段在哪个范围内。 如果它在第一个范围内,我想将“1”分配给第一个 data.frame 的字段“fin”,如果它在第二个范围内,我想分配“2”等等。

所以这是第二个 data.frame,其中包含我需要的一些条件:

Range1  Range2  Range3  Range4  ID
0.5     9.9     29.9    >30    360
0.5     15.9    49.9    >50    361
0       4.9     24.9    >25    362

首先我想我不需要声明 Range4,因为它已经是 Range3 中包含的信息。我删除了所有数字范围的初始值,因为我只需要一个数字来检查(或者我认为)。 ID 360 的同一行可以写成:

Range1  Range2  Range3    Range4    ID
 0.5    0.6-9.9  10-29.9    >30    360

所以我的猜测是做这样的事情:

esame$fin<-ifelse (esame$media<0.6 & datofinale$id_poll=="360", "1", "0")

我可以用另一个“ifelse”语句替换“0”值并手动继续。 有没有更快的方法来做到这一点? (包含所有条件的列表实际上比示例大得多)。

感谢您的建议。

【问题讨论】:

    标签: r dataframe


    【解决方案1】:

    不太好,但这应该可以:

    require(dplyr)
    
    inner_join(Data,Data1,by=c("id_poll"="ID")) %>% rowwise() %>% 
            mutate(fin = findInterval(media,c(-Inf,Range1,Range2,Range3),left.open=TRUE)) 
    

    【讨论】:

      【解决方案2】:

      可重现的数据

      esame <- structure(list(media = c(5.33, 0.06833333, 0, NA, 0.82, 0.3416667, 
      0, 0, 0, NA, 0.615, 0, 0, NA, 0, 0, 0, 1.298333), id_poll = 360:377, 
      fin = c(1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
      0L, 0L, 0L, 0L, 0L)), .Names = c("media", "id_poll", "fin"
      ), row.names = c(NA, -18L), class = c("data.table", "data.frame"
      ), .internal.selfref = <pointer: 0x0000000014320788>)
      
      df1 <- structure(list(Range1 = c(0.5, 0.5, 0), Range2 = c(9.9, 15.9, 
      4.9), Range3 = c(29.9, 49.9, 24.9), Range4 = c(">30", ">50", 
      ">25"), ID = 360:362), .Names = c("Range1", "Range2", "Range3", 
      "Range4", "ID"), row.names = c(NA, -3L), class = c("data.table", 
      "data.frame"), .internal.selfref = <pointer: 0x0000000014320788>)
      

      dplyr 解决方案

      使用case_when

      library(dplyr)
      df2 <- left_join(esame1, df1, by=c("id_poll" = "ID")) %>%
               mutate(fin = case_when( media > Range3 ~ 4,
                                       media > Range2 ~ 3,
                                       media > Range1 ~ 2,
                                       media <= Range1 ~ 1,
                                       is.na(Range1) == T ~ 0))  # else case
      

      输出

              media  ID fin Range1 Range2 Range3 Range4
      1  5.33000000 360   2    0.5    9.9   29.9    >30
      2  0.06833333 361   1    0.5   15.9   49.9    >50
      3  0.00000000 362   1    0.0    4.9   24.9    >25
      4          NA 363   0     NA     NA     NA   <NA>
      5  0.82000000 364   0     NA     NA     NA   <NA>
      

      【讨论】:

      • 你可以跳过rename(),直接做left_join(esame, df1, by = c("id_poll" = "ID"))
      • 真正的好且易于理解的解决方案。谢谢!
      • 谢谢@StevenBeaupré
      • 你能想出一个使用 plyr 包而不是 dplyr 的解决方案吗?我在我的代码中使用 plyr,我认为加载两者都会出现一些问题,特别是在使用 summarise 函数时。
      • @PaoloVeronesi 只要在加载dplyr 之前加载plyr,就应该没问题。您还应该考虑加载tidyverse,其中包含plyrdplyr,可能会帮助您避免此问题
      【解决方案3】:

      我们可以将范围data.frame中的每一行视为一个向量,询问当前媒体值是否大于这个向量中的值。

      为简单起见,我假设第一个 data.frame 中的所有值在第二个 data.frame 中都有一个对应对象,并且它们都以相同的方式排序。

      for(i in 1:nrow(esame))  {
        greater.than <- esame[i,1]>range[i,1:3] #this returns a vector of TRUE (greater than this range) and FALSE (within) you want the first FALSE
        esame$fin <- max(which(greater.than))+1 #returns the position of the last TRUE +1, which is the position of the first FALSE
      }
      

      【讨论】:

      • 不错的解决方案,但我不太喜欢 R 中的循环...无论如何感谢您的建议
      【解决方案4】:

      dat - 第一个 df,tad - 第二个。如果NA,它将放置0,嵌套ifelse(),并假设第一个范围是从0到当前值。但是显示一些示例结果以检查它是否正常工作。

      dat$fin <- sapply(1:nrow(dat), function(x) ifelse(dat[x,1] >= tad[x,1] & !is.na(dat[x,1]), 1, ifelse(dat[x,1] >= tad[x,2] & !is.na(dat[x,1]), 2, ifelse(dat[x,1] >= tad[x,3] & !is.na(dat[x,1]), 3, 0))))
      
      >dat
             media id_poll fin
      1 5.33000000     360   1
      2 0.06833333     361   0
      3 0.00000000     362   1
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-24
        • 2022-01-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多