Как определить значения до и после последовательности НС - PullRequest
0 голосов
/ 11 февраля 2020

У меня есть набор данных измерений 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, который является средним значением всех стандартных значений смежных стандартных серий и назначен всем выборкам, измеренным между этими двумя стандартными циклами.

Например, этот новый столбец будет иметь значение 592,4 (mean(c(618,621,625,534,564))) для строк с 1 по 15 включительно. И он будет иметь значение 549,2 (mean(c(546,549,553,534,564))) для всех строк от 16 до 36 включительно.

Есть ли простой способ сделать это с помощью dplyr? Следует ли собирать и организовывать данные в другом формате, чтобы облегчить эту проблему?

Ответы [ 2 ]

0 голосов
/ 11 февраля 2020

ОБНОВЛЕНИЕ

Первоначально я неправильно понял запрос. Вот ответ, который должен дать вам то, что вы ищете.

@ Ответ 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(), так что все стандартные значения находятся в одном столбце.

Затем данные группируются по стандартному представлению и упорядочиваются по стандартному представителю и группе образцов. Я БЫ. Это настраивает создание дополнительного столбца со вторым набором стандартных значений, которые вы хотите связать с этой группой, используя mutate() и lag().

Поворачивая снова, вы снова гарантируете, что все ваши стандартные значения находятся в одном столбце, и теперь все связаны с их желаемыми идентификаторами группы выборок.

Затем все, что осталось сделать, это summarise() по группе выборок и объединить с исходным набором данных smpl.grp.

DATA (с истинным NA s)

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
0 голосов
/ 11 февраля 2020

Это была интересная проблема. Я приветствовал бы любого, у кого есть лучший ответ. Технически это делается в dplyr, но в основном это базовый рабочий процесс R, который принудительно превращается в оператор Tidyverse без реального использования кода Tidyverse. Я думаю, что это общее решение, но я пришел к нему методом проб и ошибок.

Сначала создайте пример data с истинными значениями NA вместо строки символов "NA". Затем найдите индексы строк для первого и второго стандартного прогона, которые соответствуют каждой строке данных. Это делается с помощью оператора, который корректно обрабатывает крайние случаи для строк 1, 15 и 36. Наконец, go через каждую строку data и усредняйте все значения для обоих стандартных прогонов вместе, чтобы получить одно среднее значение - для этого необходимо преобразовать его в вектор и удалить NA значений.

код для создания входных данных

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

код для обработки данных

std_rows = which(!is.na(data$number.stds))
data <- data %>% 
  mutate(index1 = sapply(1:nrow(data), 
                         function(i) max(c(1,std_rows[which(i > std_rows)]))),
         index2 = sapply(1:nrow(data), 
                         function(i) min(std_rows[-1][which(i <= std_rows[-1])])))

data %>%
  mutate(standard_mean = 
           apply(data, 1, function(x) mean(unlist(data[x[c("index1", "index2")], grep('std.value', names(data))]), na.rm = TRUE)))

output

# A tibble: 36 x 8
     co2 number.stds std.value.1 std.value.2 std.value.3 index1 index2 standard_mean
   <dbl>       <dbl>       <dbl>       <dbl>       <dbl>  <dbl>  <int>         <dbl>
 1   464           3         618         621         625      1     15          592.
 2   345          NA          NA          NA          NA      1     15          592.
 3   389          NA          NA          NA          NA      1     15          592.
 4   831          NA          NA          NA          NA      1     15          592.
 5   374          NA          NA          NA          NA      1     15          592.
 6   323          NA          NA          NA          NA      1     15          592.
 7   486          NA          NA          NA          NA      1     15          592.
 8   542          NA          NA          NA          NA      1     15          592.
 9   429          NA          NA          NA          NA      1     15          592.
10   624          NA          NA          NA          NA      1     15          592.
11   359          NA          NA          NA          NA      1     15          592.
12   612          NA          NA          NA          NA      1     15          592.
13   738          NA          NA          NA          NA      1     15          592.
14   720          NA          NA          NA          NA      1     15          592.
15   520           2         534         564          NA      1     15          592.
16   454          NA          NA          NA          NA     15     36          549.
17   499          NA          NA          NA          NA     15     36          549.
18   616          NA          NA          NA          NA     15     36          549.
19   952          NA          NA          NA          NA     15     36          549.
20   805          NA          NA          NA          NA     15     36          549.
21   582          NA          NA          NA          NA     15     36          549.
22   646          NA          NA          NA          NA     15     36          549.
23   566          NA          NA          NA          NA     15     36          549.
24   781          NA          NA          NA          NA     15     36          549.
25   745          NA          NA          NA          NA     15     36          549.
26   615          NA          NA          NA          NA     15     36          549.
27   639          NA          NA          NA          NA     15     36          549.
28   750          NA          NA          NA          NA     15     36          549.
29   780          NA          NA          NA          NA     15     36          549.
30  1119          NA          NA          NA          NA     15     36          549.
31   584          NA          NA          NA          NA     15     36          549.
32  1345          NA          NA          NA          NA     15     36          549.
33  1020          NA          NA          NA          NA     15     36          549.
34  1038          NA          NA          NA          NA     15     36          549.
35  1419          NA          NA          NA          NA     15     36          549.
36  1136           3         546         549         553     15     36          549.

В соответствии с запросом строки 1-15 включают среднее значение всех пяти значений из строк 1 и 15, объединенных, а строки 16-26 включают среднее значение всех пяти значений из строк 15 и 36, вместе взятых.

...