#r #time-series #dplyr
#r #временные ряды #dplyr
Вопрос:
Я хотел бы вычислить среднее значение переменной в data.frame в R из строки, другая переменная которой начинает иметь постоянное значение. Обычно я использую dplyr для задач такого типа базы данных, но я не понимаю, как это сделать, вот пример:
s<-"no Spc PSize
2 0 6493
2 0 9281
2 12 26183
2 12 36180
2 12 37806
2 12 37765
3 12 36015
3 12 26661
3 0 14031
3 0 5564
3 1 17701
3 1 20808
3 1 31511
3 1 44746
3 1 50534
3 1 54858
3 1 58160
3 1 60326"
d<-read.delim(textConnection(s),sep="",header=T)
mean(d[1:10,3])
sd(d[1:10,3])
Из строки 11 переменная spc имеет постоянное значение, так что это то место, где я хочу разделить data.frame
mean(d[11:18,3])
sd(d[11:18,3])
Я могу вычислить это вручную, но идея не в этом…
Ответ №1:
Вариант 1: Использование rleid
из data.table
пакета:
d %>%
group_by(rlid = rleid(Spc)) %>%
summarise(mean_size = mean(PSize), sd_size = sd(PSize)) %>%
slice(n())
дает:
# A tibble: 1 × 3
rlid mean_size sd_size
<int> <dbl> <dbl>
1 4 42330.5 16866.59
Вариант 2: Использование rle
:
startrow <- sum(head(rle(d$Spc)$lengths, -1)) 1
d %>%
slice(startrow:n()) %>%
summarise(mean_size = mean(PSize), sd_size = sd(PSize))
дает:
mean_size sd_size
1 42330.5 16866.59
Вариант 3: Если вы хотите вычислить для двух групп (последней и других), вам следует использовать group_by
вместо filter
и создать новый вектор группировки ( rep_vec
) с rle
:
rep_vec <- c(sum(head(rle(d$Spc)$lengths, -1)), tail(rle(d$Spc)$lengths, 1))
d %>%
group_by(grp = rep(c('others','last_group'), rep_vec)) %>%
summarise(mean_size = mean(PSize), sd_size = sd(PSize))
что дает:
grp mean_size sd_size
(chr) (dbl) (dbl)
1 last_group 42330.5 16866.59
2 others 23597.9 13521.32
Если вы хотите включить строки, вы можете изменить код на:
d %>%
mutate(rn = row_number()) %>%
group_by(grp = rep(c('others','last_group'), rep_vec)) %>%
summarise(mean_size = mean(PSize), sd_size = sd(PSize), rows = paste0(range(rn), collapse=':'))
что дает:
grp mean_size sd_size rows
<chr> <dbl> <dbl> <chr>
1 last_group 42330.5 16866.59 11:18
2 others 23597.9 13521.32 1:10
Ответ №2:
Вы можете сделать это, добавив столбец, который проверяет, соответствует ли запись указанному выше значению, затем используйте cumsum
, чтобы найти места, где изменяется количество. Я group_by
сделал это и вычислил нужные вам сводки — я также добавил вывод, какие строки были включены, чтобы продемонстрировать, откуда он был взят.
d %>%
mutate(
row = 1:n()
, isDiff = Spc != lag(Spc, default = Spc[1])
, whichGroup = cumsum(isDiff)) %>%
group_by(whichGroup, Spc) %>%
summarise(mean = mean(PSize)
, sd = sd(PSize)
, whichRows = paste(range(row), collapse = ":"))
Дает:
whichGroup Spc mean sd whichRows
<int> <int> <dbl> <dbl> <chr>
1 0 0 7887.0 1971.414 1:2
2 1 12 33435.0 5486.794 3:8
3 2 0 9797.5 5987.073 9:10
4 3 1 42330.5 16866.591 11:18
Если вам нужна только последняя группа, о которой я не могу сказать из вашего сообщения, делаете вы это или нет, вы могли бы вместо этого использовать filter
, вот так:
d %>%
mutate(
row = 1:n()
, isDiff = Spc != lag(Spc, default = Spc[1])
, whichGroup = cumsum(isDiff)) %>%
filter(whichGroup == max(whichGroup)) %>%
summarise(Spc = Spc[1]
, mean = mean(PSize)
, sd = sd(PSize)
, whichRows = paste(range(row), collapse = ":"))
Что дает:
Spc mean sd whichRows
1 1 42330.5 16866.59 11:18
Судя по комментарию, вам, похоже, нужна последняя группа против в остальном вы можете получить это с помощью такого подхода:
d %>%
mutate(
row = 1:n()
, isDiff = Spc != lag(Spc, default = Spc[1])
, whichGroup = cumsum(isDiff)) %>%
group_by(isLast = whichGroup == max(whichGroup)) %>%
summarise(mean = mean(PSize)
, sd = sd(PSize)
, whichRows = paste(range(row), collapse = ":"))
что дает:
isLast mean sd whichRows
<lgl> <dbl> <dbl> <chr>
1 FALSE 23597.9 13521.32 1:10
2 TRUE 42330.5 16866.59 11:18
Комментарии:
1. Я хотел бы рассчитать две группы, последнюю и остальные.
2. @Leosar — смотрите последнюю правку для версии, которая сравнивает последнюю группу со всеми остальными
3. Мне кажется, что этот подход более гибкий, чем @Procrastinatus-максимальный
4. @Leosar Я думаю, что подход Марка хороший, но он не более гибкий, imo (также не менее гибкий).
Ответ №3:
Итак, вы хотите найти индекс, в котором средний вектор начинает быть постоянным? Вы можете взять diff()
вашего вектора и посмотреть, в первый раз это отличается от нуля. Например,
vec <- c(1,2,3,4,5,5,5,6,6,6)
diff(vec)
differences <- rev(diff(vec))
# distance from the end of first non-zero
min.dist <- min(which(differences != 0))
# take difference
length(vec) - min.dist 1
Это последнее значение должно дать вам индекс, с которого вектор начинает быть постоянным.