Подмножество dataframes с ошибкой цикла

S31 спросил: 13 июня 2018 в 10:56 в: r

У меня есть цикл, который вызывает у меня не только временные проблемы, так как длится много времени для работы в наборе данных 30k, но не обеспечивает правильный вывод. p>

interval <- days(10)df <- data.frame(CompanyID = c(23512, 51250, 12515, 51250, 52512, 51250), 
                 openingDate = as.Date(c("1999-07-15", "1995-02-01", 
                 "2001-01-25", "1995-02-04", "2004-07-08", "1996-05-25")),
                 Rev = c(1000, 2000, 4000, 5000, 5500, 2050))for(id in unique(df$CompanyID)){
    df[, c("groupID")] <- NA
    df[, c("updatedRev")] <- df$RevtempDF <- df %>% filter(CompanyID == id)if(nrow(tempDF) == 1){
  #arbitrary unique ID
  df$groupID[df$CompanyID == id] <- paste(id) 
}else{
  dfDateRange <- tempDF[order(tempDF$openingDate),]  while(nrow(dfDateRange) > 0) { # until table is empty    earliest_date <- dfDateRange$openingDate[1] #earliest date within subset
    within_dates <- dfDateRange %>% filter(openingDate <= earliest_date + interval) 
    # all data within the interval    # values to replace in subset that falls within date range
    # Revenue
    df$updatedRev[(df$CompanyID == id) &
                    (df$openingDate %in% within_dates$openingDate )] <-
    sum(within_dates$Rev)    # Generate Group ID 
    df$groupID[(df$CompanyID == id) &
                 (df$openingDate %in% within_dates$openingDate)] <- paste(id)    # moving on to rows outside of date range
    dfDateRange <- dfDateRange %>% 
       filter(dfDateRange$openingDate > (earliest_date + interval))  }
 }
}  

Перевод этого кода:

  • Возьмите в большой фреймворк данных, создайте колонку идентификатора группы temp, которая будет использоваться позже, и обновленный столбец Rev, который будет перезаписана позже в зависимости от условий
  • Для каждого уникального идентификатора CompanyID создайте фрейм данных и назначьте новый идентификатор
  • Если имеется несколько случаев CompanyID, мы подмножаемся при условии, что все инциденты попадают в определенный диапазон дат.
  • Для тех, кто попадает в указанный диапазон дат, мы переопределяем значения доходов и присваиваем идентификатор группы этой группе (в этом примере строки 2 и 4)
  • Для тех, кто выходит за пределы диапазона дат, перейдите к следующей самой ранней дате открытия - и посмотрите, какие строки попадают в этот диапазон, и выполните шаги, начинающиеся с цикла for

Two вопросы об этом. Когда я возвращаю dataframe после запуска цикла, я возвращаюсь

> df
  CompanyID openingDate  Rev groupID updatedRev
1     23512  1999-07-15 1000    <NA>       1000
2     51250  1995-02-01 2000    <NA>       2000
3     12515  2001-01-25 4000    <NA>       4000
4     51250  1995-02-04 5000    <NA>       5000
5     52512  2004-07-08 5500   52512       5500
6     51250  1996-05-25 2050    <NA>       2050

Когда я вернусь:

  CompanyID openingDate  Rev groupID updatedRev
1     23512  1999-07-15 1000   23512       1000
2     51250  1995-02-01 2000   51250       7000
3     12515  2001-01-25 4000   12515       4000
4     51250  1995-02-04 5000   51250       7000
5     52512  2004-07-08 5500   52512       5500
6     51250  1996-05-25 2050   51250       2050

note, updatedRev не обновлялся, чтобы заменить значения суммированными значениями дубликатов 51250 CompanyID, которые попадают в 10-дневный диапазон друг от друга.

Мой другой вопрос, когда я обертываю это функцией в функции - скажем test() и запустить функцию test(df) - df не изменяется. Почему это?

Примечание. Я буду корректировать группу позже, чтобы быть более точным, так что строка 6 может быть дифференцирована между Row 2 & 4. Просто хочу получить этот вопрос, так как это просто настройка линии.


1 ответ

Есть решение
Maurits Evers ответил: 13 июня 2018 в 03:21

При условии, что я правильно понял вашу постановку проблемы (к сожалению, ваш код и перевод довольно заумные, см. мой комментарий ниже), следующий подход tidyverse воспроизводит ваш ожидаемый результат

library(tidyverse)
df %>%
    rowid_to_column("row") %>%                      
    mutate(
        openingDate = as.Date(openingDate),
        groupID = CompanyID) %>%
    group_by(groupID) %>%
    arrange(openingDate) %>%
    mutate(
        diff = openingDate - lag(openingDate),
        grp = cumsum(+!(is.na(diff) | diff < 10))) %>%
    group_by(groupID, grp) %>%
    mutate(updatedRev = sum(Rev)) %>%
    ungroup() %>%
    select(-diff, -grp) %>%
    arrange(row)
## A tibble: 6 x 6
#    row CompanyID openingDate   Rev groupID updatedRev
#  <int>     <dbl> <date>      <dbl>   <dbl>      <dbl>
#1     1    23512. 1999-07-15  1000.  23512.      1000.
#2     2    51250. 1995-02-01  2000.  51250.      7000.
#3     3    12515. 2001-01-25  4000.  12515.      4000.
#4     4    51250. 1995-02-04  5000.  51250.      7000.
#5     5    52512. 2004-07-08  5500.  52512.      5500.
#6     6    51250. 1996-05-25  2050.  51250.      2050.

Объяснение: Записи группы по groupID = CompanyID, сортировка по openingDate, вычисление различий между последовательными openingDate s и предоставление grp метки на основе того, будет ли последовательный openingDate s в течение 10 дней; затем введите группу groupID и grp и создайте updatedRev как сумму сгруппированных значений Rev. Последними шагами являются tidying & переупорядочивая data.frame, чтобы воспроизвести ожидаемый результат.

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


В вашем коде есть несколько проблем, одна из которых - одна из них, но большинство из них связаны с циклами for и while , Например, я не понимаю, что вы пытаетесь сделать в

for(id in unique(df$CompanyID)){
    df[, c("groupID")] <- NA
    df[, c("updatedRev")] <- df$Rev

Вы не используете id где-либо внутри for, и вы можете добиться того же, просто сделав

df$groupID <- NA
df$updatedRev <- df$Rev

Update

Чтобы получить уникальный groupID s для наблюдений которые отличаются от >=10 дней, вы можете конкатенировать companyID и grp

df %>%
rowid_to_column("row") %>%
mutate(openingDate = as.Date(openingDate)) %>%
group_by(CompanyID) %>%
arrange(openingDate) %>%
mutate(
    diff = openingDate - lag(openingDate),
    grp = cumsum(+!(is.na(diff) | diff < 10)),
    groupID = paste(CompanyID, grp, sep = "_")) %>%
group_by(groupID, grp) %>%
mutate(updatedRev = sum(Rev)) %>%
ungroup() %>%
select(-diff, -grp) %>%
arrange(row)
## A tibble: 6 x 6
#    row CompanyID openingDate   Rev groupID updatedRev
#  <int>     <dbl> <date>      <dbl> <chr>        <dbl>
#1     1    23512. 1999-07-15  1000. 23512_0      1000.
#2     2    51250. 1995-02-01  2000. 51250_0      7000.
#3     3    12515. 2001-01-25  4000. 12515_0      4000.
#4     4    51250. 1995-02-04  5000. 51250_0      7000.
#5     5    52512. 2004-07-08  5500. 52512_0      5500.
#6     6    51250. 1996-05-25  2050. 51250_1      2050.
S31 ответил: 13 июня 2018 в 12:38
Спасибо! Я знаю, что код повсюду, использовал с кем-то другой подход и оценил лучший метод! Два вопроса: что делает cumsum(+? Кроме того, если бы я надеялся получить идентификатор группы только для тех строк, которые упали в том же диапазоне дат, возможно ли это? Как вы можете видеть, я просто использовал CompanyID, но в идеале я пытался сделать его более уникальным. Таким образом, строки 2 & 4, будет отличаться от строки 6 с использованием идентификатора группы?
Maurits Evers ответил: 13 июня 2018 в 03:20
@ S31 cumsum(+!...) возвращает кумулятивную сумму логического условия, так что TRUE равно 0 и FALSE равно 1 , grp получает приращение, если есть наблюдение за >=10 дней, кроме предыдущего наблюдения. Это делается для того, чтобы мы суммировали правильные записи в каждой группе. Чтобы предоставить уникальный groupID, вы можете объединить companyID и метку grp; Я обновил свой ответ, чтобы продемонстрировать. Взгляни, пожалуйста.
S31 ответил: 13 июня 2018 в 05:12
Человек, блестящий. Спасибо.
Maurits Evers ответил: 14 июня 2018 в 07:48
Вы очень рады @ S31!

Дополнительное видео по вопросу: Подмножество dataframes с ошибкой цикла

Подмножество

Подмножество. Видеоурок по алгебре 9 класс

Подмножество, собственное подмножество и надмножество (видео 2) | Множества | Алгебра