我有一个湖泊中许多不同站点的深度数据帧,我希望每个站点都有从最小到最大的完整深度序列(以及用NAs填充的缺失值)。
我使用tidyr::complete来做这个,但是它的行为很奇怪。当深度四舍五入到小数点后0位时,代码按预期运行,但是当数据到十分之一米时,深度类发生了一些奇怪的事情,并且完成了一些组合(并且值填充了NA),即使我已经有了该深度的数据。
有人经历过这种情况吗?我认为它与深度类有关,但我还没有完全弄清楚它或如何避免它。
library(dplyr)
b <- data.frame(site = c(rep("A", 10), rep("B", 10)),
depth = c(seq(0.1, 0.8, 0.1), 1.0, 1.1, seq(0.3, 0.5, 0.1), seq(0.9, 1.5, 0.1)),
value = round(runif(20, 0, 5), 1))
b2 <- b %>%
mutate(site = factor(site)) %>%
group_by(site) %>%
tidyr::complete(depth = seq(min(depth),
max(depth),
by = 0.1)) %>%
arrange(site, depth)
原始数据帧的一些深度被复制,这是意想不到的。
class(b2$depth)
unique(b2$depth)
b2[b2$site == "B", ]
当我从数字转换回数字时,深度似乎已经恢复到我所期望的,尽管我仍然需要用NAs删除重复的深度。
class(as.numeric(as.character(b2$depth)))
unique(as.numeric(as.character(b2$depth)))
如果深度没有小数点,行为似乎更容易预测。
a <- data.frame(site = c(rep("A", 10), rep("B", 10)),
depth = c(1:4, 6:11, 3:5, 8, 10, 12:16),
value = round(runif(20, 0, 5), 1))
a2 <- a %>%
mutate(site = factor(site)) %>%
group_by(site) %>%
tidyr::complete(depth = seq(min(depth),
max(depth),
by = 1)) %>%
arrange(site, depth)
class(a2$depth)
unique(a2$depth)
a2[a2$site == "B", ]
确实,complete()
正在产生额外的无法解释的元素。
我认为,当complete()
匹配序列产生的数字和原始数据中的数字时,它将(1.4 == 1.4)计算为FALSE
并将它们作为两个不同的数字返回。我做了一个小测试,我确实得到了FALSE
!为了避免这种情况,我们需要四舍五入,并确保"深度"值在原dataframe和那些由seq()
是相同的。
b <- data.frame(site = c(rep("A", 10), rep("B", 10)),
depth = c(seq(0.1, 0.8, 0.1), 1.0, 1.1, seq(0.3, 0.5, 0.1), seq(0.9, 1.5, 0.1)),
value = round(runif(20, 0, 5), 1))
b$depth <- round(b$depth,2) #crucial to do it here and not via mutate()
b2 <- b %>%
mutate(site = factor(site)) %>%
group_by(site) %>%
tidyr::complete(depth = round(seq(min(depth),
max(depth),
by = 0.1),
2)) %>%
ungroup()
检查B站点的输出是否正常
> b2[b2$site == "B",]
# A tibble: 13 × 3
site depth value
<chr> <chr> <dbl>
1 B 0.3 3.4
2 B 0.4 0.7
3 B 0.5 4.5
4 B 0.6 NA
5 B 0.7 NA
6 B 0.8 NA
7 B 0.9 1.4
8 B 1 1.2
9 B 1.1 1.3
10 B 1.2 3.3
11 B 1.3 2.1
12 B 1.4 0.9
13 B 1.5 1.2
这个问题,据我所知,是由于seq()
商店它生成的值。注意这些值是如何不精确的:
> v2 = seq(.3,1.4, by = .1)
> print(v2, digits =16)
[1] 0.3000000000000000 0.4000000000000000 0.5000000000000000 0.6000000000000001
[5] 0.7000000000000000 0.8000000000000000 0.9000000000000001 1.0000000000000000
[9] 1.1000000000000001 1.2000000000000000 1.3000000000000000 1.3999999999999999
1.3999以来……不等于1.4,则complete()
没有将两个1.4的值连接起来。这就是副本产生的原因。