Использование одного определенного значения на группу для каждого другого значения в группе - PullRequest
0 голосов
/ 04 января 2019

У меня есть конкретный вопрос программирования относительно R. Я хочу применить пользовательскую функцию ко всему набору данных, но значения в функции должны измениться по сравнению с той группой, к которой она принадлежит. Вот набор данных, который похож на тот, с которым я работаю

set.seed(123)
df <- data.frame(group = c(rep("one", 10), rep("two", 9), rep("three", 11)),
         slot = c(1:10, 1:9, 1:11),
         x = sample(100, 30))

И функция

RI_fun <- function(x, y) {
((x - y)/ y) * 100
}

Реальный набор данных больше, но структура такая же. Небольшая информация о реальном наборе данных: это серия измерений (слотов) в выборке (группе), где я хочу, чтобы первое измерение (слот == 1) было y в пользовательской функции (RI_fun)

Я хочу создать новый столбец, который является выводом пользовательской функции, где x = df $ x, а y - значение x, где df $ slot == 1 для каждой группы.

Я пытался создать цикл for, но безуспешно. Моя идея состояла в том, чтобы сделать значение y оператором if else, где он проверял df $ group и применял df $ x, где slot == 1 и group == group, которые только что были проверены.

Вот моя попытка:

for (i in seq_along(df$group)) {
RI[i] = RI_fun(x = df$x[i],
               y = (ifelse(df$group == df$group[i],
                           df$x[df$slot == 1 & df$group == df$group[i]],
                           NA)))

Однако вывод:

[1]   0.00000 172.41379  41.37931 196.55172 213.79310 -82.75862  72.41379 186.20690  75.86207  44.82759        NA
[12]        NA        NA        NA        NA        NA        NA        NA        NA        NA        NA        NA
[23]        NA        NA        NA        NA        NA        NA        NA        NA

Когда я вручную проверил, каким должен быть вывод, он показал, что цикл for работает правильно до [11], где он больше не работает. Я пробовал некоторые другие циклы for, похожие на этот, но это тот, где я был ближе всего к желаемому результату.

Буду признателен за любую помощь, которую вы получите. Если я не достаточно ясно, пожалуйста, спросите, и я постараюсь сделать это более ясно.

Ответы [ 2 ]

0 голосов
/ 04 января 2019

Проблема с оператором ifelse. Когда вы вызываете ifelse (df $ group == df $ group [i] ...), он возвращает false, как только df $ group [i]! = Df $ group [1]; возвращает результат самого первого сравнения. Насколько я вижу, вам не нужно ifelse. Следующий код работал для меня (хотя вы должны выполнить ручную проверку, чтобы убедиться, что он правильный).

df <- data.frame(group = c(rep("one", 10), rep("two", 9), rep("three", 11)),
                 slot = c(1:10, 1:9, 1:11),
                 x = sample(100, 30))

RI_fun <- function(x, y) {
  ((x - y)/ y) * 100
}

RI <- rep(NA, 30)

for (i in seq_along(df$group)) {
  RI[i] = RI_fun(x = df$x[i],
                 y = (df$x[df$slot == 1 & df$group == df$group[i]]))
}

RI
0 голосов
/ 04 января 2019

Отличный вопрос, красиво отформатированный на воспроизводимом примере! Престижность!

В R обычно вам не нужно беспокоиться об использовании циклов. R изначально векторизован, поэтому мы можем выразить себя через векторы. Переходя к data.frames, идея та же, и добавив пакет dplyr, мы получим несколько простых функций.

Сначала я покажу, что вы хотите:

library(dplyr)
df %>% group_by(group) %>%
  mutate(y=x[slot==1])
as.data.frame(.Last.value)
   group slot  x  y
1    one    1 30 30
2    one    2 72 30
3    one    3 88 30
4    one    4  5 30
5    one    5 55 30
6    one    6 42 30
7    one    7 11 30
8    one    8 53 30
9    one    9 73 30
10   one   10 87 30
11   two    1 52 52
12   two    2 82 52
13   two    3 78 52
14   two    4 59 52
15   two    5 12 52
16   two    6 95 52
17   two    7  1 52
18   two    8 70 52
19   two    9 66 52
20 three    1 69 69
21 three    2 79 69
22 three    3 80 69
23 three    4 21 69
24 three    5 94 69
25 three    6 75 69
26 three    7 25 69
27 three    8 15 69
28 three    9 74 69
29 three   10 31 69
30 three   11 43 69

Итак, мы можем подтвердить, что мы получаем правильные значения x и y. Попробуйте убрать строку group_by и посмотрите, что получится.

Удовлетворенный тем, что мы получаем соответствующие значения x и y, включите вашу функцию:

df %>% group_by(group) %>%
  mutate(RI=RI_fun(x, x[slot==1]))

Если вы попытались удалить строку group_by, вы получили ошибку. Это потому, что mutate хочет использовать значение, либо 1 для всего вектора (столбца), либо значение для элемента в столбце. Так что же происходит, если у вас есть несколько слотов == 1 на группу? Что ж, вам придется решить, как бороться с отклонениями от ваших требований.

EDIT:

Причина, по которой ваш цикл for не работает должным образом, связана с ifelse в точке y. Просто замените на

for (i in seq_along(df$group)) {
RI[i] = RI_fun(x = df$x[i],
               y = df$x[df$slot == 1 & df$group == df$group[i]])
}

и все должно работать нормально.

Это связано с тем, что ifelse векторизовано; для каждого элемента в аргументе test (first) (df$group == df$group[i]) он возвращает соответствующий элемент в элементе yes (второй) или no (третий).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...