У меня есть следующий набор данных в R
dat <- data.frame(t = rep(seq(1, 5, 1),4), id = rep(c(rep("A",5), rep("B",5), rep("C",5), rep("D",5)), 1),
x = 1:20, y = 51:70, h = c(rep(1,10), rep(0,10) ) )
require(dplyr)
dat <- arrange(dat, t)
Набор данных представляет собой панель с t в качестве временной переменной и id в качестве идентификатора субъекта. Мне нужно присоединить дополнительную строку, в которой я вычисляю сумму x, умноженную на y для оставшихся субъектов во время t, и делю ее на стандартное отклонение переменных x для оставшихся субъектов во время t. В этой новой строке должен отображаться ноль для субъектов с h == 0.
Например, для субъекта A в момент времени t == 1 операция следующая: (6 * 56 + 11 * 61 + 16 * 66) / sd(c(6, 11, 16)). Аналогичная операция для субъекта B в момент времени t == 1 - это (1 * 51 + 11 * 61 + 16 * 66) / sd(c(1, 11, 16)). Однако для субъектов C и D в новой строке будет отображаться только 0.
Какой самый быстрый способ сделать это без цикла? Я считаю, что пакет dplyr самый быстрый, но я новичок в нем и не знаю, как с ним бороться. В своей попытке я сначала группирую по времени, а затем собираю переменные, но получаю предупреждение и несколько переменных удаляются. Я не уверен, как выбирать переменные для каждой группы.
dat %>%
group_by(t) %>%
gather(key, value, -t)
# Warning message:
# attributes are not identical across measure variables;
# they will be dropped
КОНДИЦИОНИРОВАНИЕ
Как включить в предыдущую операцию условие, чтобы в следующей таблице операция вычислялась только тогда, когда cond == id. Например, для первой строки у нас будет: 0, потому что все субъекты B, C и D имеют значения, отличные от их id (cond - это A). Для строки 6 вместо этого используется (2*52 + 12*62 + 17*67) / sd(c(2,12,17)).
dat <- data.frame(t = rep(seq(1, 5, 1),4), id = rep(c(rep("A",5), rep("B",5), rep("C",5), rep("D",5)), 1),
x = 1:20, y = 51:70, h = c(rep(1,10), rep(0,10) ) )
dat <- arrange(dat, t)
dat <- data.frame(dat, cond = c("B", "A", "A", "A", "A", "B", "C", "D", "A", "B", "D", "C", "A", "D", "C", "A", "A", "C", "C", "B") )
dat
# t id x y h cond
# 1 1 A 1 51 1 B
# 2 1 B 6 56 1 A
# 3 1 C 11 61 0 A
# 4 1 D 16 66 0 A
# 5 2 A 2 52 1 A
# 6 2 B 7 57 1 B
# 7 2 C 12 62 0 C
# 8 2 D 17 67 0 D
# 9 3 A 3 53 1 A
# 10 3 B 8 58 1 B
# 11 3 C 13 63 0 D
# 12 3 D 18 68 0 C
# 13 4 A 4 54 1 A
# 14 4 B 9 59 1 D
# 15 4 C 14 64 0 C
# 16 4 D 19 69 0 A
# 17 5 A 5 55 1 A
# 18 5 B 10 60 1 C
# 19 5 C 15 65 0 C
# 20 5 D 20 70 0 B
Предлагаемое решение
dat %>%
filter(id == cond) %>%
group_by(t) %>%
mutate(new = h * ((sum(x *y) - (x * y))/map_dbl(row_number(), ~ sd(x[-.x])))) %>%
bind_rows(dat %>% filter(id != cond))
работает очень хорошо, но частично, так как создает NaN из умножения 0 * Inf. Вместо этого я хотел бы иметь 0, когда условия не применяются или когда стандартное отклонение в знаменателе равно 0. Большое спасибо!





После группировки по 't' создайте 'новый' столбец, взяв разницу sum продуктов 'x' и 'y' с продуктом 'x' и 'y' (чтобы исключить продукт текущей строки) и разделив его, получив sd элементов 'x', пройдя цикл по индексу строки (row_number()), который будет использоваться для исключения текущей строки, и умножим на 'h' так, чтобы мы получили 0, где 'h' равно 0.
library(tidyverse)
out <- dat %>%
group_by(t) %>%
mutate(new = h * ((sum(x *y) - (x * y))/map_dbl(row_number(),
~ sd(x[-.x]))))
head(out, 4)
# A tibble: 4 x 6
# Groups: t [1]
# t id x y h new
# <dbl> <fct> <int> <int> <dbl> <dbl>
#1 1 A 1 51 1 413.
#2 1 B 6 56 1 233.
#3 1 C 11 61 0 0
#4 1 D 16 66 0 0
Извините, если это сбивало с толку. Интересно, как модифицировать линейку mutate с дополнительным кондиционированием. Например, вычисление описанной выше операции (сумма оставшихся субъектов / стандартное отклонение) с использованием только данных для таких субъектов, как id == cond (при условии, что cond принимает значения либо в A, либо в B).
@ Андрей Может быть, вы имели в виду dat %>% filter(id == cond) %>% group_by(t) %>% mutate(new = h * ((sum(x *y) - (x * y))/map_dbl(row_number(), ~ sd(x[-.x])))) %>% bind_rows(dat %>% filter(id != cond))
Да! это почти все! он просто создает NaN вместо нулей. Я добавил пример в текст! Большое спасибо, Акрун!
Я думаю, что добавление этих двух строк в ваш последний код поможет: replace_na(list(new = 0)) %>% arrange(t, id). Большое спасибо!
Это прекрасно работает! Спасибо! Знаете ли вы, как расширить код, чтобы я рассматривал при суммировании в числителе и в sd в знаменателе только лиц, удовлетворяющих условию? Например, предположим, что это данные
dat <- data.frame(t = rep(seq(1, 5, 1),4), id = rep(c(rep("A",5), rep("B",5), rep("C",5), rep("D",5)), 1), x = 1:20, y = 51:70, h = c(rep(1,10), rep(0,10) ), cond = sample(c("A", "B"), 20, replace = T) ), и я получаюnewтолько от субъектов, соответствующихid != cond.