Как итеративно разделить все предыдущие наблюдения по последнему наблюдению в столбце фрейма данных на группы в R, а затем сохранить результат - PullRequest
0 голосов
/ 10 апреля 2020

У меня есть следующий фрейм данных:

data <- data.frame("Group" = c(1,1,1,1,1,1,1,1,2,2,2,2), 
"Days" = c(1,2,3,4,5,6,7,8,1,2,3,4), "Num" = c(10,12,23,30,34,40,50,60,2,4,8,12))

Мне нужно взять последнее значение в Num и разделить его на все предыдущие значения. Затем мне нужно перейти от второго к последнему значению в Num и делать то же самое, пока я не достигну первого значения в каждой группе.

Отредактировано на основе комментариев ниже: На простом языке и показывая всю математику, начиная с первой группы, как предлагается ниже, я пытаюсь добиться следующего: Возьмите 60 (последнее значение в группе 1) и:

Day Num Res
7 60/50  1.2
6 60/40  1.5
5 60/34  1.76
4 60/30  2
3 60/23  2.60
2 60/12  5
1 60/10  6

Затем сохраните только строку, имеющую значение 2, так как я не забочусь о других (я хочу, чтобы значение было больше или равно 2, которое ближе всего к 2), и возвращает день этого значения, который также равен 4. Затем перейдите к 50 и сделайте следующее:

Day Num Res
6 50/40  1.25
5 50/34  1.47
4 50/30  1.67
3 50/23  2.17
2 50/12  4.17
1 50/10  5

Затем сохраните только строку, имеющую значение 2.17, и верните день этого значения, который также равен 3. Затем перейдите к 40 и сделайте то же самое снова, перейдите к 34, затем 30, затем 23, затем 12, последнее значение (или значение первого дня), которое меня не волнует. Затем перейдите к последнему значению следующей группы (12) и повторите тот же подход для этой группы (12/8, 12/4, 12/2; 8/4, 8/2; 4/2)

Я хотел бы сохранить результаты этих делений, но только самый последний результат, который больше или равен 2. Я также хотел бы вернуть день, когда был достигнут результат. По сути, я пытаюсь рассчитать время удвоения для каждого дня. Я также хотел бы, чтобы это было сгруппировано Группой. Обычно я бы использовал dplyr для этого, но я не уверен, как связать al oop с dyplr, чтобы воспользоваться group_by. Кроме того, я мог бы пропустить lapply или некоторые его вариации. Мой ожидаемый кадр данных с результатами в идеале должен быть таким:

data2 <- data.frame(divres = c(NA,NA,2.3,2.5,2.833333333,3.333333333,2.173913043,2,NA,2,2,3), 
obs_n =c(NA,NA,1,2,2,2,3,4,NA,1,2,2))

data3 <- bind_cols(data, data2)

Я пробовал этот первый l oop, чтобы вычислить деление, но я потерян, как перейти к следующему последнему значению в каждом группа. Прямо сейчас это игнорирует группу, хотя я, очевидно, не сказал это группе, так как мне неясно, как это сделать за пределами dplyr.

for(i in 1:nrow(data)) 
   data$test[i] <- ifelse(!is.na(data$Num), last(data$Num)/data$Num[i] , NA)

При запуске я также получаю следующую ошибку:
количество заменяемых элементов не кратно длине замены

Чтобы сохранить разделение, я пробовал это :

division <- function(x){
  if(x>=2){
    return(x)
  } else {
    return(FALSE)
  }
}
for (i in 1:nrow(data)){
   data$test[i]<- division(data$test[i])
}

Теперь этот подход работает, но только если мне нужно выполнить это один раз для последнего наблюдения и только если я применю его к 1 группе. У меня 209 групп и много дней, которые мне нужно было бы проверить. Я не уверен, как сложить первое для l oop с помощью функции деления, и я также совершенно потерян, как сделать это по группам и перейти к следующим последним значениям. Мы ценим любые предложения.

Ответы [ 2 ]

1 голос
/ 10 апреля 2020

Вы можете изменить функцию division, чтобы обрабатывать вектор и возвращать фрейм данных с двумя столбцами divres и ind. Последний - это индекс строки, который будет использоваться для вычисления obs_n, как показано ниже:

    division <- function(x){
  lenx <- length(x)
  y    <- vector(mode="numeric", length = lenx)
  z    <- vector(mode="numeric", length = lenx)
  for (i in lenx:1){
    y[i] <- ifelse(length(which(x[i]/x[1:i]>=2))==0,NA,x[i]/x[1:i] [max(which(x[i]/x[1:i]>=2))])
    z[i] <- ifelse(is.na(y[i]),NA,max(which(x[i]/x[1:i]>=2)))
  }
  df <- data.frame(divres = y, ind = z)
  return(df)
}

Проверьте выход функции division, созданной выше, используя data$Num в качестве входа

> division(data$Num)
     divres ind
1        NA  NA
2        NA  NA
3  2.300000   1
4  2.500000   2
5  2.833333   2
6  3.333333   2
7  2.173913   3
8  2.000000   4
9        NA  NA
10 2.000000   9
11 2.000000  10
12 3.000000  10

Используйте cbind, чтобы объединить вышеуказанный вывод с фрейм данных data1, используйте pipes и mutate из dplyr для поиска значения obs_n в Day, используя ind, выберите соответствующие столбцы для генерации желаемого фрейма данных data2:

data2 <- cbind.data.frame(data, division(data$Num)) %>% mutate(obs_n = Days[ind]) %>% select(-ind)

Выход

> data2
   Group Days Num   divres obs_n
1      1    1  10       NA    NA
2      1    2  12       NA    NA
3      1    3  23 2.300000     1
4      1    4  30 2.500000     2
5      1    5  34 2.833333     2
6      1    6  40 3.333333     2
7      1    7  50 2.173913     3
8      1    8  60 2.000000     4
9      2    1   2       NA    NA
10     2    2   4 2.000000     1
11     2    3   8 2.000000     2
12     2    4  12 3.000000     2
0 голосов
/ 10 апреля 2020

Вы можете создать функцию с помощью для l oop, чтобы получить желаемый день, как указано ниже. Затем используйте это, чтобы получить divres в мутации dplyr .

obs_n <- function(x, days) {
  lst <- list()
  for(i in length(x):1){
    obs <- days[which(rev(x[i]/x[(i-1):1]) >= 2)]
    if(length(obs)==0)
     lst[[i]] <- NA
    else
      lst[[i]] <- max(obs)
  }
  unlist(lst)
}

Затем используйте dense_rank, чтобы получить номер строки, соответствующий каждому obs_n. Это необходимо в случае, если дни не являются последовательными, то есть имеют пробелы.

library(dplyr)

data %>%
  group_by(Group) %>%
  mutate(obs_n=obs_n(Num, Days), divres=Num/Num[dense_rank(obs_n)])

# A tibble: 12 x 5
# Groups:   Group [2]
   Group  Days   Num obs_n divres
   <dbl> <dbl> <dbl> <dbl>  <dbl>
 1     1     1    10    NA  NA   
 2     1     2    12    NA  NA   
 3     1     3    23     1   2.3 
 4     1     4    30     2   2.5 
 5     1     5    34     2   2.83
 6     1     6    40     2   3.33
 7     1     7    50     3   2.17
 8     1     8    60     4   2   
 9     2     1     2    NA  NA   
10     2     2     4     1   2   
11     2     3     8     2   2   
12     2     4    12     2   3

Объяснение плотных рангов (из Википедии). В плотном ранжировании элементы, которые сравниваются одинаково, получают одинаковый номер ранжирования, а следующий (ые) элемент (ы) получают непосредственно следующий рейтинговый номер.

x <- c(NA, NA, 1,2,2,4,6)
dplyr::dense_rank(x)
# [1] NA, NA, 1 2 2 3 4

Сравнение с рангом (метод по умолчанию = "средний"). Обратите внимание, что NA включены в конце по умолчанию.

rank(x)
[1] 6.0 7.0 1.0 2.5 2.5 4.0 5.0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...