首页 > 解决方案 > 如何识别一系列 NA 之前和之后的值

问题描述

我有一组从实验室仪器中获取的 CO2 测量数据。在整个数据收集过程中也偶尔运行标准。模拟数据集如下所示:

tibble(co2=c(464,345,389,831,374,323,486,542,429,624,359,612,738,720,520,454,499,616,952,805,582, 646,566,781,745,615,639,750,780,1119,584,1345,1020,1038,1419,1136),
number.stds=c(3,rep('NA',13),2,rep('NA',20),3),
std.value.1=c(618,rep('NA',13),534,rep('NA',20),546),
std.value.2=c(621,rep('NA',13),564,rep('NA',20),549),
std.value.3=c(625,rep('NA',34),553)) -> data

co2是测量数据,number.stds是测量的标准数量,std.value.1通过std.value.3是不同的标准读数。

我想生成一个新列std.value,它是相邻标准运行的所有标准值的平均值,并分配给在这两个标准运行之间测量的所有样本。

例如,对于第mean(c(618,621,625,534,564))1 行到第 15 行(含),此新列的值将是 592.4 ( )。对于从 16 到 36 的所有行(包括 16 和 36),它的值将是 549.2 ( mean(c(546,549,553,534,564)))。

有没有一种简单的方法可以用 dplyr 做到这一点?是否应该以不同的格式收集和组织数据以使这个问题更容易?

标签: rdplyrdata-manipulation

解决方案


更新

我最初误解了这个请求。这是一个答案,应该可以为您提供所需的内容。

@qdread 的回答简洁明了。这个更长,但坚持 tidyverse 语法。

library(dplyr)
library(tidyr)

data <- data %>% mutate(grp.start = if_else(!is.na(number.stds), 1, 0),
                        smpl.grp = cumsum(grp.start),
                        smpl.grp = if_else(!is.na(number.stds) & row_number() != 1, lag(smpl.grp), smpl.grp)) %>% 
  select(smpl.grp, everything(), -grp.start)


data.2 <- data %>%
  filter(!is.na(number.stds)) %>%
  select(smpl.grp, std.value.1:std.value.3) %>% 
  mutate(smpl.grp = if_else(row_number() == 1, 0, smpl.grp)) %>% #assigns first row a grp # of 0 but keeps its standard values in our dataset, takes care of edge issues going forward.
  pivot_longer(std.value.1:std.value.3, names_to = "standard.rep", names_prefix = "std.value.", values_to = "std.values") %>% 
  select(standard.rep, everything()) %>%
  group_by(standard.rep) %>% 
  arrange(standard.rep, smpl.grp) %>% 
  mutate(std.values.2 = lag(std.values)) %>% 
  pivot_longer(std.values:std.values.2, names_to = "std.grps", values_to = "std.values") %>% 
  group_by(smpl.grp) %>% 
  summarise(std.n = sum(!is.na(std.values)), std.avg = mean(std.values, na.rm = T)) %>% 
  left_join(select(data, smpl.grp, co2), .)

data.2
# A tibble: 36 x 4
   smpl.grp   co2 std.n std.avg
      <dbl> <dbl> <int>   <dbl>
 1        1   464     5    592.
 2        1   345     5    592.
 3        1   389     5    592.
 4        1   831     5    592.
 5        1   374     5    592.
 6        1   323     5    592.
 7        1   486     5    592.
 8        1   542     5    592.
 9        1   429     5    592.
10        1   624     5    592.
# … with 26 more rows

首先,我为每组样本(“smpl.grp”)分配了一个唯一标识符,您希望将其与不同的标准平均值集进行比较

然后,我们可以删除无关的行并仅使用相关数据:样本组编号和标准值。

下一步会稍微整理数据,pivot_longer()以便所有标准值都在一个列中。

然后数据按标准代表分组,并按标准代表和样品组 ID 排列。这设置了生成一个附加列,其中包含您希望使用mutate()和与该组关联的第二组标准值lag()

通过再次旋转,您再次确保所有标准值都在一个列中,现在所有标准值都与其所需的样本组 ID 相关联。

然后剩下要做的就是summarise()按样本组并加入smpl.grp的原始数据集。

DATA(带真NAs)

tibble(co2=c(464,345,389,831,374,323,486,542,429,624,359,612,738,720,520,454,499,616,952,805,582, 646,566,781,745,615,639,750,780,1119,584,1345,1020,1038,1419,1136),
       number.stds=c(3,rep(NA_real_,13),2,rep(NA_real_,20),3),
       std.value.1=c(618,rep(NA_real_,13),534,rep(NA_real_,20),546),
       std.value.2=c(621,rep(NA_real_,13),564,rep(NA_real_,20),549),
       std.value.3=c(625,rep(NA_real_,34),553)) -> data

推荐阅读