我有一个格式为“long”的data.frame df
。
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
的唯一元素不存在的行?
在这种情况下,我想删除df[3,]
,因为对于df$time
,时间戳33仅适用于网站A,而不适用于网站B和网站C.
期望的输出:
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()
这样的矢量化函数。
答案 0 :(得分: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
来自Matthew的编辑
尼斯。或者更直接的方式:
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))]
答案 1 :(得分: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
解决方案更好的方法。而不是查找&#34; 1&#34;的游程长度,将删除与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
因此,如果我们想要包含至少有两个网站有时间戳的网站,我们可以将行>= length(levels(df$site))
(在此示例中为3)更改为>= length(levels(df$site))-1
(显然,2)。
不确定这个解决方案是否对您有用,但我想我会分享它以显示我们与R的解决方案的灵活性。