4

df「long」形式のdata.frameがあります。

df <- data.frame(site = rep(c("A","B","C"), 1, 7),
                 time = c(11,11,11,22,22,22,33),
                 value = ceiling(rnorm(7)*10))
df <- df[order(df$site), ]

df
  site time value
1    A   11    12
2    A   22   -24
3    A   33   -30
4    B   11     3
5    B   22    16
6    C   11     3
7    C   22     9

質問

df$timeレベルごとにの一意の要素が存在しない行を削除するにはどうすればよいdf$siteですか?

この場合、タイムスタンプ33はサイトAにのみ存在し、サイトBとサイトCには存在しないdf[3,]ため、を削除します。df$time

必要な出力:

df.trimmed
  site time value
1    A   11    12
2    A   22   -24
4    B   11     3
5    B   22    16
6    C   11     3
7    C   22     9

data.frameには、簡単に800k行と200k固有のタイムスタンプがあります。ループを使用したくありませんが、この場合のようにapply()、またはlapply()この場合のベクトル化された関数の使用方法がわかりません。

4

2 に答える 2

5

data.tableパッケージを使用した別の可能な解決策は次のとおりです。

unTime <- unique(df$time)

library(data.table)

DT <- data.table(df, key = "site")

(notInAll <- unique(DT[, list(ans = which(!unTime %in% time)), by = key(DT)]$ans))
# [1] 3

DT[time %in% unTime[-notInAll]]

#      site time value
# [1,]    A   11     3
# [2,]    A   22    11
# [3,]    B   11    -6
# [4,]    B   22    -2
# [5,]    C   11   -19
# [6,]    C   22   -14

マシュー
ニースから編集。またはもう少し直接的な方法:

DT = as.data.table(df)
tt = DT[,length(unique(site)),by=time]
tt
   time V1
1:   11  3
2:   22  3
3:   33  1

tt = tt[V1==max(V1)]      # See * below
tt
   time V1
1:   11  3
2:   22  3

DT[time %in% tt$time]
   site time value
1:    A   11     7
2:    A   22    -2
3:    B   11     8
4:    B   22   -10
5:    C   11     3
6:    C   22     1

すべてのサイトに時間がない場合、最終結果が空になるはずのとき(Benがコメントで指摘したように)、*上記のステップは次のようになります。

tt = tt[V1==length(unique(DT$site))]
于 2012-06-21T12:16:41.927 に答える
2

あなたrleのために働きますか?

df <- df[order(df$time), ]
df <- subset(df, time != rle(df$time)$value[rle(df$time)$lengths == 1])
df <- df[order(df$site), ]
df
##   site time value
## 1    A   11    17
## 4    A   22    -3
## 2    B   11     8
## 5    B   22     5
## 3    C   11     0
## 6    C   22    13

データを再検討すると、このソリューションはニーズに対して単純すぎる可能性があります。

アップデート

これが私が上に置いた解決策よりも良いはずのアプローチですrle。「1」のランレングスを探すのではなく、の結果の特定の条件に一致しない行を削除しますtable(df$site, df$time)。説明のために、さらにいくつかの偽のデータを追加しました。

df <- data.frame(site = rep(c("A","B","C"), 1, 7),
                 time = c(11,11,11,22,22,22,33),
                 value = ceiling(rnorm(7)*10))
df2 <- data.frame(site = rep(c("A","B","C"), 1, 7),
                 time = c(14,14,15,15,16,16,16),
                 value = ceiling(rnorm(7)*10))
df <- rbind(df, df2)
df <- df[order(df$site), ]

temp <- as.numeric(names(which(colSums(with(df, table(site, time)))
                               >= length(levels(df$site)))))
df2 <- merge(df, data.frame(temp), by.x = "time", by.y = "temp")
df2 <- df2[order(df2$site), ]
df2
##   time site value
## 3   11    A    -2
## 4   16    A    -2
## 7   22    A     2
## 1   11    B   -16
## 5   16    B     3
## 8   22    B    -6
## 2   11    C     8
## 6   16    C    11
## 9   22    C   -10

サイトと時間の組み合わせを表にして要約した結果は次のとおりです。

colSums(with(df, table(site, time)))
## 11 14 15 16 22 33 
##  3  2  2  3  3  1 

したがって、少なくとも2つのサイトにタイムスタンプがあるサイトを含めることに関心がある場合は、行>= length(levels(df$site))(この例では3)を>= length(levels(df$site))-1(明らかに2)に変更できます。

このソリューションがあなたにとってまったく役立つかどうかはわかりませんが、Rを使用したソリューションの柔軟性を示すために共有したいと思いました。

于 2012-06-21T11:44:05.220 に答える