替换R数据帧中除1行之外的重复值

时间:2016-06-11 17:20:18

标签: r dataframe

如何根据ID将R数据帧的特定列的重复值替换为NA(第一行除外)。举个例子:

x <- data.frame(id=c("p1","p1","p1","p2","p2"),date=c("d1","d1","d1","d2","d2"))

并且应该导致以下结果:

x2 <- data.frame(id=c("p1","p1","p1","p2","p2"),date=c("d1","NA","NA","d2","NA"))

我必须维护每个id多行的数据结构,只是不希望重复日期值而是一次。

由于

4 个答案:

答案 0 :(得分:4)

data.table方法:

library(data.table)
x3<-data.table(x)

x3[, `:=` (date = ifelse(duplicated(date), NA, date)), by = id]
x3

id date
p1   d1
p1   NA
p1   NA
p2   d2
p2   NA

一般情况下,建议谨慎使用:=,因为您所做的调整是永久性的。但是,在这种情况下,这就是我们所追求的,并使用<-来保存,以根据需要定义/重新定义列。有关详细信息,请参阅?data.table

答案 1 :(得分:3)

选项1:基本R方法是使用ave()date中的每个组替换重复的NA值和id值。

x$date <- ave(
    x$date, 
    x$id, 
    FUN = function(a) replace(a, duplicated(a), NA_integer_)
)

提供更新的x数据

  id date
1 p1   d1
2 p1 <NA>
3 p1 <NA>
4 p2   d2
5 p2 <NA>

上述方法适用于date中的多个值,用NA替换重复项。如果它只是你所追求的第一组值,你可以使用上面或下面的代码,这可能会更快。

ave(
    x$date,
    x$id,
    FUN = function(a) c(a[1], a[-1][NA])
)

此代码获取每个组中的第一个值,并用NA替换所有其余值。目前尚不清楚您想要哪一个,因为您的示例数据每个id组只有一个值。

选项2:使用 data.table 包的替代方案。由于NA是合乎逻辑的,date[NA]只需将值转换为NA而不更改数据类型。

library(data.table)
setDT(x)[duplicated(date), date := date[NA], by = id]

给出了

   id date
1: p1   d1
2: p1   NA
3: p1   NA
4: p2   d2
5: p2   NA

答案 2 :(得分:2)

<强> BENCHMARK

library(data.table)
library(microbenchmark)
dff <- data.frame(id=c("p1","p1","p1","p2","p2"),date=c("d1","d1","d1","d2","d2"))

func_Bryan.Goggin <- function(x){x3<-data.table(x);x3[, `:=` (date = ifelse(duplicated(date), NA, date)), by = id];}
func_Richard.Scriven <- function(x){x$date <- ave(x$date, x$id, FUN = function(a) replace(a, duplicated(a), NA_integer_));}
func_r2evans <- function(x){groupedx <- by(x, x$date, function(df) {within(df, date <- c(as.character(date[1]), rep(NA, nrow(df) - 1)))});Reduce(rbind, groupedx);}
microbenchmark(func_Bryan.Goggin(dff), func_Richard.Scriven(dff), func_r2evans(dff))

Unit: microseconds
                      expr     min      lq     mean   median       uq      max neval
    func_Bryan.Goggin(dff) 791.436 816.827 886.0153 848.9770 880.9765 1733.408   100
 func_Richard.Scriven(dff) 130.103 146.630 157.8821 154.1410 164.3570  305.277   100
         func_r2evans(dff) 590.423 615.662 668.7100 637.8975 656.5260 1607.511   100

修改

我将func_Richard.Scriven2排除在基准之外,因为它将通过引用进行调用。

答案 3 :(得分:1)

这有效:

x <- data.frame(id=c("p1","p1","p1","p2","p2"),
                date=c("d1","d1","d1","d2","d2"))
groupedx <- by(x, x$date, function(df) {
                 within(df, date <- c(as.character(date[1]), rep(NA, nrow(df) - 1)))
               })
Reduce(rbind, groupedx)
#   id date
# 1 p1   d1
# 2 p1 <NA>
# 3 p1 <NA>
# 4 p2   d2
# 5 p2 <NA>

(我使用as.character是因为你在data.frame中使用了因子,没有它就把字符串转换成它们的因子整数。如果你使用实际的字符串,你应该可以省略它。)