使用数据框中其他列的条件替换向量中的重复值

时间:2017-01-23 14:34:02

标签: r if-statement dataframe duplicates

我有一个非常类似的问题: Identify and replace duplicates elements from a vector

我需要根据数据框中其他列的条件替换序列BUT中出现的列中的重复值。

我有一个这样的数据框(加上一些额外的列):

 ID<- c("1V","1V","1V","1V","2V","2V","4V","4V","4V","4V","4V")
 year<- c(1,1,1,2,1,1,2,2,3,3,3)
 sequence<- c(1,2,2,1, 1,2,1,2,1,1,1)
 score <- c(5,5,5,5,10,10,10,10,11,11,11)
 examp <- data.frame(ID,year, sequence, score)

> examp
   ID year sequence score
1  1V    1        1     5
2  1V    1        2     5
3  1V    1        2     5
4  1V    2        1     5
5  2V    1        1    10
6  2V    1        2    10
7  4V    2        1    10
8  4V    2        2    10
9  4V    3        1    11
10 4V    3        1    11
11 4V    3        1    11

我需要的是用NA替换每个ID,年份和序列中的重复分数。与分数结合的序列也应该用NA替换。因此,不会删除任何行,只删除特定条目。

> examp
   ID year sequence score
1  1V    1        1     5
2  1V    1        2     5
3  1V    1        NA    NA
4  1V    2        2     5
5  2V    1        1    10
6  2V    1        2    10
7  4V    2        1    10
8  4V    2        2    10
9  4V    3        1    11
10 4V    3        NA   NA
11 4V    3        NA   NA

保留所有行。不同的ID /年/序列可能会出现相同的分数,但只有在这三个列的每个唯一组合中,才能替换重复的分数。

来自其他链接问题的单个向量和解决方案的示例:

 a <- 1 1 1 2 3 2 2 2 2 1 0 0 0 0 2 3 4 4 1 1
 ifelse(a == c(a[1]-1,a[(1:length(a)-1)]) , 0 , a)
 [1] 1 0 0 2 3 2 0 0 0 1 0 0 0 0 2 3 4 0 1 0

我不确定如何使用多个标准调整上述问题中的上述代码。可能吗? 首先,最重要的是取代分数,但如果有人有解决方案来取代分数和顺序,我会非常高兴。

2 个答案:

答案 0 :(得分:1)

在基数R中,您可以使用子集和is.na

is.na(examp[duplicated(examp[1:3]), c("sequence", "score")]) <- TRUE

examp
   ID year sequence score
1  1V    1        1     5
2  1V    1        2     5
3  1V    1       NA    NA
4  1V    2        1     5
5  2V    1        1    10
6  2V    1        2    10
7  4V    2        1    10
8  4V    2        2    10
9  4V    3        1    11
10 4V    3       NA    NA
11 4V    3       NA    NA

这里,ID year sequence返回一个逻辑向量,即data.frame的长度,表示前三个变量的行是否与前一行重复。 c("sequence", "score")确定要替换的列。然后在重复行的那些列中将is.na设置为TRUE。

更长但更易读的版本是使用变量名而不是它们的位置。

is.na(examp[duplicated(examp[c("ID", "year", "sequence")]), c("sequence", "score")]) <- TRUE

从长远来看,如果由于合并或其他操作导致位置发生变化,这也更安全。从现在起六个月后审查代码时,阅读/解释也可能更容易。

答案 1 :(得分:0)

我们可以使用data.table。将'data.frame'转换为'data.table'(setDT(examp)),按'ID','年'分组,我们得到行索引(.I),其中列'序列',是duplicated然后set数据集列'sequence'中的值,'得分'到NA。这应该是非常有效的,因为我们正在设置

library(data.table)
i1 <- setDT(examp)[, .I[duplicated(sequence)], .(ID, year)]$V1
 for(j in 3:4){
   set(examp, i = i1, j=j, value = NA)
 }

examp
#    ID year sequence score
# 1: 1V    1        1     5
# 2: 1V    1        2     5
# 3: 1V    1       NA    NA
# 4: 1V    2        1     5
# 5: 2V    1        1    10
# 6: 2V    1        2    10
# 7: 4V    2        1    10
# 8: 4V    2        2    10
# 9: 4V    3        1    11
#10: 4V    3       NA    NA
#11: 4V    3       NA    NA

dplyr

library(dplyr)
examp %>%
  group_by(ID, year) %>%
  mutate_each(funs(replace(., duplicated(.), NA)))

使用base R,我们可以做一个紧凑的选项

examp[duplicated(examp[1:3]), 3:4] <- NA
examp
#   ID year sequence score
#1  1V    1        1     5
#2  1V    1        2     5
#3  1V    1       NA    NA
#4  1V    2        1     5
#5  2V    1        1    10
#6  2V    1        2    10
#7  4V    2        1    10
#8  4V    2        2    10
#9  4V    3        1    11
#10 4V    3       NA    NA
#11 4V    3       NA    NA

或另一个选项replace lapply

examp[3:4] <- lapply(examp[3:4], function(x) replace(x, duplicated(examp[1:3]), NA))