4

私はdata.frame

ID  code1   code2  code3
A    143     143    144
A    35      453     35
A             35     15
B    46      46      45
B    12      43     765
C    255     455     344
C    343     343     343
C    343     23      23

各コードは一度に表示されます

ID は繰り返すことができます。実際の data.frame は非常に大きい

ID  code1   code2  code3
A    143             144
A    35      453     
A             35     15
B    46              45
B    12      43      765
C    255     455     344
C    343          
C    343     23      

ありがとう

4

2 に答える 2

4

これはどう?

df[, 2:4][t(apply(df[,2:4], 1, duplicated))] <- NA

編集:はるかに高速な基本ソリューション:

for (i in 2:(ncol(df)-1)) {
    for (j in (i+1):ncol(df)) {
        chk <- df[[i]] == df[[j]]
        df[[j]][chk] <- NA
    }
}

上記の 2 つの方法と、より大きなデータに対するAnandaMahtoreshape2および方法のベンチマークを次に示します。右とインデックスdata.tableを使用すると、最速のようです。for-loopij

ベンチマーク結果:

require(microbenchmark)
microbenchmark(ar.f <- arun.f(df), ar.s <- arun.s(df), 
               an.f <- ananda.ave(df), 
               an.s <- ananda.dt(copy(DT)), times=10)

# Unit: milliseconds

#                 expr       min        lq   median        uq       max neval
#           arun.f(df) 4816.3937 5197.0626 6402.454 6955.9380 7534.6912    10
#           arun.s(df)  114.8372  118.7971  149.284  202.6081  297.4787    10
#       ananda.ave(df) 2877.7936 3288.5935 3650.660 3985.5390 4111.9064    10
#  ananda.dt(copy(DT)) 3383.1229 3861.6379 4432.751 4776.6108 5368.6504    10

データの作成:

set.seed(1234)
df <- cbind(data.frame(ID = rep(letters[1:20], each=1e4)), stringsAsFactors=FALSE),  
            matrix(sample(1:10, 6 * 1e5, replace=TRUE), ncol=3))
names(df)[2:4] <- paste0("code", 1:3)

私の最初のバージョン:

arun.f <- function(df) {
    df[, 2:4][t(apply(df[,2:4], 1, duplicated))] <- NA
    df
}

私の2番目のバージョン:

arun.s <- function(df) {
    for (i in 2:(ncol(df)-1)) {
        for (j in (i+1):ncol(df)) {
            chk <- df[[i]] == df[[j]]
            df[[j]][chk] <- NA
        }
    }
    df
}

アナンダのave+reshape2ソリューション:

library(reshape2)
ananda.ave <- function(df) {
    df$ID2 <- with(df, ave(ID, ID, FUN = seq_along))
    m.df <- melt(df, id.vars=c("ID", "ID2"))
    m.df[duplicated(m.df[setdiff(names(m.df), "variable")]), "value"] <- NA
    dcast(m.df, ID + ID2 ~ variable)
}

アナンダのdata.table解決策:

(より最適化するために少し変更されました)

library(data.table)
DT <- data.table(df)
ananda.dt <- function(dt) {
    temp <- dt[, list(ID2 = 1:.N, Value = unlist(.SD, use.names=FALSE)), by ="ID"]
    temp[duplicated(temp), Value := NA]
    out <- setnames(temp[, as.list(Value), by=list(ID, ID2)], 3:5, paste0("code", 1:3))
}
于 2013-04-28T12:44:23.513 に答える
1

このソリューションは多少非効率的である可能性がありますが、それは主にワイドとロングとワイドの間でデータを変換するためです。ただし、「長い」形式のデータを操作する方が簡単な場合があります。

複数の行にまたがる ID があるため、最初に 2 番目の ID を生成します。

mydf$ID2 <- with(mydf, ave(ID, ID, FUN = seq_along))

次に、melt「reshape2」パッケージから使用して、データを長い形式にします。

library(reshape2)
m.df <- melt(mydf, id.vars=c("ID", "ID2"))

長い形式のデータを使用すると、重複を特定してNA.

m.df[duplicated(m.df[setdiff(names(m.df), "variable")]), "value"] <- NA

長い形式のデータに満足している場合。そこで止まれ。幅の広いフォームに戻したい場合は、dcast(再び「reshape2」から) を使用します。

dcast(m.df, ID + ID2 ~ variable)
#   ID ID2 code1 code2 code3
# 1  A   1   143    NA   144
# 2  A   2    35   453    NA
# 3  A   3    NA    35    15
# 4  B   1    46    NA    45
# 5  B   2    12    43   765
# 6  C   1   255   455   344
# 7  C   2   343    NA    NA
# 8  C   3   343    23    NA

参考までに、これはベース R でも実行可能ですが、構文はより不器用です (「reshape2」の同等物よりもパフォーマンスが優れている可能性がありますが)。

mydf$ID2 <- with(mydf, ave(ID, ID, FUN = seq_along))
m.df <- cbind(mydf[c("ID", "ID2")], 
              stack(mydf[setdiff(names(mydf), c("ID", "ID2"))]))
m.df[duplicated(m.df[setdiff(names(m.df), "ind")]), "values"] <- NA
cbind(mydf[c("ID", "ID2")], unstack(m.df, values ~ ind))

更新:可能なdata.table解決策

data.tableデータが大きいと述べているため、調査することをお勧めします。考えられる解決策の 1 つを次に示します (ただし、@Arun には共有するためのより直接的な解決策がある場合があります)。

library(data.table)
DT <- data.table(mydf)

## Creates your long data.table
temp <- DT[, list(ID2 = 1:.N, Value = unlist(.SD)), by ="ID"]
## Changes duplicates to NA and adds in the "Code" column
temp[duplicated(temp), Value := NA][, Variable := rep(names(DT)[-1], 
                                                      each = nrow(DT))]
## "Reshapes" the data from long to wide
temp[, as.list(setattr(Value, 'names', Variable)), by=list(ID, ID2)]
#    ID ID2 code1 code1 code1
# 1:  A   1   143    NA   144
# 2:  A   2    35   453    NA
# 3:  A   3    NA    35    15
# 4:  B   1    46    NA    45
# 5:  B   2    12    43   765
# 6:  C   1   255   455   344
# 7:  C   2   343    NA    NA
# 8:  C   3   343    23    NA
于 2013-04-28T16:19:13.197 に答える