如何根据另一个数据框的多个条件在数据框中分配值

时间:2017-08-16 11:13:20

标签: r dataframe

我有两个数据框,一个由称为'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的'media'字段的范围。 如果它在第一个范围内,我想将“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”值,然后手动继续。 有没有更快的方法呢? (包含所有条件的列表实际上比示例大得多)。

感谢您的任何建议。

4 个答案:

答案 0 :(得分: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)) 

答案 1 :(得分:1)

可重复数据

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>

答案 2 :(得分:0)

我们可以将范围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
}

答案 3 :(得分:0)

dat - 第一个df,tad - 秒。它会0 NA,嵌套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