Фильтрация идентификаторов на основе указанной разницы в значениях - PullRequest
2 голосов
/ 26 мая 2019

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

    ID<-c("aaa","bbb","ccc","ddd","eee","fff","ggg","hhh","iii","aaa","bbb","ccc","ddd","eee","fff","ggg","hhh","iii","aaa","bbb","ccc","aaa","bbb","ccc")
    Condition<-c("Pre","Pre","Pre","Pre","Pre","Pre","Pre","Pre","Pre","Post","Post","Post","Post","Post","Post","Post","Post","Post","Pre","Pre","Pre","Post","Post", "Post")
    Score<-c(23,20,19,15,22,22,20,19,18,17,17,19,20,22,22,14,15,10,23,23,21,20,18,11)
    df<-cbind(ID,Condition,Score)
    df<-as.data.frame(df)
    df$Condition<-as.factor(df$Condition)

Основная проблема здесь заключается в том, что есть идентификаторы, которые появляются в данных, как до, так и после, дважды.

Я попытался использовать решение dplyr, чтобы выбрать соответствующие столбцы из основного фрейма данных, а затем использовать tidyverse и функцию spread для преобразования в широкоформатный формат, потому что оттуда я могуВыяснить различия достаточно легко.Однако есть определенная проблема, с которой я столкнулся.Это не будет работать, потому что есть повторяющиеся случаи, когда идентификатор снова появляется в данных (например, идентификаторы aaa, bbb & ccc).

     df2<-df%>%
     group_by(ID)%>%
     spread(Condition, Score)

Это приводит меня к следующему сообщению об ошибке: -

Ошибка: каждая строка вывода должна быть идентифицирована уникальной комбинацией клавиш.Ключи разделены на 12 строк: * 10, 22 * ​​11, 23 * 12, 24 * 1, 19 * 2, 20 * 3, 21 Вам нужно создать уникальный идентификатор с помощью tibble :: rowid_to_column ()?

В идеале, результат, который я бы искал, выглядит примерно так: -

    #improved
    ID      Pre       Post     Difference
    aaa      23        17           -6
    bbb      20        17           -3
    ggg      20        14           -6
    hhh      19        15           -4
    iii      18        10           -8
    aaa      23        20           -3
    bbb      23        18           -5
    ccc      21        11           -10


    #no improvement
    ID      Pre       Post      Difference
    ccc      19         19          0
    eee      22         22          0
    fff      22         22          0


    #worsened
    ID      Pre       Post      Difference
    ddd      15         20          +5

Или что-то в этом роде.Пока это позволяет мне включать повторные идентификаторы.В идеале я хотел бы иметь возможность дополнительно фильтровать по разнице.Так, например, если я хочу установить / отфильтровать идентификаторы с улучшенной оценкой более 5 или с ухудшенной оценкой более 5. Не забывайте, у моего фактического набора данных будет гораздо больше идентификаторов для работы, чем в примере, которыйЯ просто помирился и обеспечил.Любая помощь будет принята с благодарностью, как всегда.

Заранее спасибо:)

Ответы [ 3 ]

2 голосов
/ 26 мая 2019

Другая tidyverse возможность может быть:

df %>%
 mutate_if(is.factor, as.character) %>%
 mutate(Score = as.numeric(Score)) %>%
 group_by(Condition) %>%
 mutate(ID = make.unique(ID)) %>%
 group_by(ID) %>%
 mutate(Difference = Score - lag(Score)) %>%
 spread(Condition, Score) %>%
 summarise_all(max, na.rm = TRUE) %>%
 arrange(Difference)

   ID    Difference  Post   Pre
   <chr>      <dbl> <dbl> <dbl>
 1 ccc.1        -10    11    21
 2 iii           -8    10    18
 3 aaa           -6    17    23
 4 ggg           -6    14    20
 5 bbb.1         -5    18    23
 6 hhh           -4    15    19
 7 aaa.1         -3    20    23
 8 bbb           -3    17    20
 9 ccc            0    19    19
10 eee            0    22    22
11 fff            0    22    22
12 ddd            5    20    15

Вот он, во-первых, создает уникальные идентификаторы. Во-вторых, он рассчитывает разницу. Наконец, он преобразует его в широкий формат и упорядочивает в соответствии с различиями.

Если по каким-либо причинам вам нужно разделить его в соответствии с различиями, вы можете добавить последнюю строку из кода @ akrun:

df %>%
 mutate_if(is.factor, as.character) %>%
 mutate(Score = as.numeric(Score)) %>%
 group_by(Condition) %>%
 mutate(ID = make.unique(ID)) %>%
 group_by(ID) %>%
 mutate(Difference = Score - lag(Score)) %>%
 spread(Condition, Score) %>%
 summarise_all(max, na.rm = TRUE) %>%
 group_split(sign(Difference), keep = FALSE)

[[1]]
# A tibble: 8 x 4
  ID    Difference  Post   Pre
  <chr>      <dbl> <dbl> <dbl>
1 aaa           -6    17    23
2 aaa.1         -3    20    23
3 bbb           -3    17    20
4 bbb.1         -5    18    23
5 ccc.1        -10    11    21
6 ggg           -6    14    20
7 hhh           -4    15    19
8 iii           -8    10    18

[[2]]
# A tibble: 3 x 4
  ID    Difference  Post   Pre
  <chr>      <dbl> <dbl> <dbl>
1 ccc            0    19    19
2 eee            0    22    22
3 fff            0    22    22

[[3]]
# A tibble: 1 x 4
  ID    Difference  Post   Pre
  <chr>      <dbl> <dbl> <dbl>
1 ddd            5    20    15
2 голосов
/ 26 мая 2019

Можно сначала преобразовать «Score» в numeric из factor, сгруппированных по «ID» «Condition», создать столбец последовательности («rn»), spread в «широкий» форматполучите разницу между показателями «Post» и «Pre» и split в столбце sign of «Difference», чтобы создать list из tibble s

library(tidyverse)
df %>% 
   mutate(Score = as.numeric(as.character(Score))) %>% 
   group_by(ID, Condition) %>% 
   mutate(rn = row_number()) %>% 
   spread(Condition, Score) %>% 
   mutate(Difference = Post -Pre) %>% 
   ungroup %>% 
   select(-rn) %>%
   group_split(grp = sign(Difference), keep = FALSE)
#[[1]]
# A tibble: 8 x 4
#  ID     Post   Pre Difference
#  <fct> <dbl> <dbl>      <dbl>
#1 aaa      17    23         -6
#2 aaa      20    23         -3
#3 bbb      17    20         -3
#4 bbb      18    23         -5
#5 ccc      11    21        -10
#6 ggg      14    20         -6
#7 hhh      15    19         -4
#8 iii      10    18         -8

#[[2]]
# A tibble: 3 x 4
#  ID     Post   Pre Difference
#  <fct> <dbl> <dbl>      <dbl>
#1 ccc      19    19          0
#2 eee      22    22          0
#3 fff      22    22          0

#[[3]]
# A tibble: 1 x 4
#  ID     Post   Pre Difference
#  <fct> <dbl> <dbl>      <dbl>
#1 ddd      20    15          5

ПРИМЕЧАНИЕ:Не рекомендуется использовать as.data.frame(cbind, так как cbind преобразуется в matrix, а matrix может содержать только один класс, т. Е. Если есть символьный столбец, все остальные столбцы преобразуются в character и переносс as.data.frame (по умолчанию stringsAsFactors = TRUE).

df <- data.frame(...) #directly create
1 голос
/ 27 мая 2019

Адрес других ответов Score является фактором из-за вызова cbind(). Вот решения для Base R, data.table и dplyr.

Все решения обращаются к дубликату ID путем добавления дополнительной переменной Group. Это позволяет spread быть успешным.

# Base R ------------------------------------------------------------------

df <- data.frame(ID, Condition, Score)
df$Group <- ave(seq_len(nrow(df)), df$Condition, FUN = seq_along)

df_wide <- reshape(df, timevar = 'Condition', idvar = c('ID', 'Group'), direction = 'wide')
df_wide$Difference <- df_wide$Score.Post - df_wide$Score.Pre
df_wide[order(df_wide$Difference),]

# data.table --------------------------------------------------------------
library(data.table)

dt <- data.table(ID, Condition, Score)
dt[, Group := seq_len(.N), by = Condition]

dt_wide <- dcast(dt, ID + Group ~ Condition, value.var = 'Score')
dt_wide[, Difference := Post - Pre]
dt_wide[order(Difference),]

# dplyr -------------------------------------------------------------------
library(tidyverse)

tib <- tibble(ID, Condition, Score)

tib%>%
  group_by(Condition)%>%
  mutate(Group = row_number())%>%
  ungroup()%>%
  spread(key = 'Condition', value = 'Score')%>%
  mutate(Difference = Post - Pre)%>%
  arrange(Difference)

Для этого очень небольшого набора данных база R самая быстрая, а data.table самая медленная.

Unit: milliseconds
           expr    min      lq     mean  median      uq     max neval
     base_r_way 2.7562 2.98075 3.103155 3.05140 3.12810  6.0653   100
 data.table_way 6.6137 7.09705 8.216043 7.44250 8.01885 47.9138   100
      dplyr_way 4.7334 5.15005 5.350857 5.25085 5.40395  9.5594   100

И данные:

ID <- c("aaa","bbb","ccc","ddd","eee","fff","ggg","hhh","iii","aaa","bbb","ccc","ddd","eee","fff","ggg","hhh","iii","aaa","bbb","ccc","aaa","bbb","ccc")
Condition <- c("Pre","Pre","Pre","Pre","Pre","Pre","Pre","Pre","Pre","Post","Post","Post","Post","Post","Post","Post","Post","Post","Pre","Pre","Pre","Post","Post", "Post")
Score <- as.integer(c(23,20,19,15,22,22,20,19,18,17,17,19,20,22,22,14,15,10,23,23,21,20,18,11))
...