Как изменить значение столбца на основе комбинации значений из двух других столбцов в R? - PullRequest
1 голос
/ 26 мая 2020

У меня есть панельные данные для 300 тысяч человек (ID). Каждый ID имеет 1 строку в год (2013-2016). На основании «Кода» определяется статус «Имя» (за год). Однако некоторые ошибки все же есть. Если один идентификатор в моем фреймворке данных имеет определенное имя в определенном году, я хочу дать всем один и тот же код и год, а также это имя для того же кода и года. В случае, если ни у кого нет имени в поле «Имя» для указанного c кода и года, тогда будет достаточно NA. Это довольно сложно, потому что идентификаторы могут переключаться с кодами в течение многих лет (не в течение года).

Например: для идентификатора № 2 имя для 2014 года должно измениться с NA на PIZZA, в зависимости от тот факт, что другой идентификатор в фрейме данных (здесь # 1) имеет "PIZZA" для того же кода и года. Тем не менее, ID # 3 и ID # 4 остаются как NA в 2016 году, потому что ни у кого с кодом 05/1234 и годом 2016 нет имени в фрейме данных.

    > str(Poging23)
tibble [16 x 5] (S3: tbl_df/tbl/data.frame)
 $ ID           : num [1:16] 1 1 1 1 2 2 2 2 3 3 ...
 $ Date_of_birth: POSIXct[1:16], format: "2000-05-25" "2000-05-25" "2000-05-25" "2000-05-25" ...
 $ Code         : chr [1:16] "01/1234" "01/1234" "01/1234" "01/1234" ...
 $ Year         : num [1:16] 2013 2014 2015 2016 2013 ...
 $ Name         : chr [1:16] "PIZZA" "PIZZA" "NA" "NA" ...

> dput(Poging23)
structure(list(ID = c(1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 
4, 4, 4), Date_of_birth = structure(c(959212800, 959212800, 959212800, 
959212800, 25315200, 25315200, 25315200, 25315200, 277862400, 
277862400, 277862400, 277862400, 1267574400, 1267574400, 1267574400, 
1267574400), class = c("POSIXct", "POSIXt"), tzone = "UTC"), 
    Code = c("01/1234", "01/1234", "01/1234", "01/1234", "01/1234", 
    "01/1234", "01/1234", "01/1234", "01/1234", "01/1234", "05/1234", 
    "05/1234", "05/1234", "05/1234", "05/1234", "05/1234"), Year = c(2013, 
    2014, 2015, 2016, 2013, 2014, 2015, 2016, 2013, 2014, 2015, 
    2016, 2013, 2014, 2015, 2016), Name = c("PIZZA", "PIZZA", 
    "NA", "NA", "NA", "NA", "PIZZA", "NA", "NA", "PIZZA", "NA", 
    "NA", "PASTA", "PASTA", "PASTA", "NA")), row.names = c(NA, 
-16L), class = c("tbl_df", "tbl", "data.frame"))

К сожалению, эти коды не работали должным образом (не учитывались изменения в коде за последние годы): Как изменить NA идентификатора на символьное значение на основе других значений / характеристик ячеек идентификатора в R?.

Изменить: я назвал NA как " NA ", потому что сначала я сделал предварительный просмотр в Excel.

Также можно изменить все имена на 1, а NA на 0, если это облегчит задачу.

Надеюсь, кто-нибудь сможет мне помочь / давать советы!

Спасибо!

Ответы [ 2 ]

1 голос
/ 27 мая 2020

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

Сначала мы создаем таблицу поиска, которая содержит для каждой комбинации Code и Year все значения в Name, которые отличаются от "NA"

library(tidyverse)

lookup <- Poging23 %>% 
  group_by(Code, Year) %>% 
  group_modify(~unique(.$Name) %>% enframe(name = NULL, value = "Name")) %>% 
  filter(Name != "NA")

# A tibble: 6 x 3
# Groups:   Code, Year [6]
#   Code     Year Name 
#   <chr>   <dbl> <chr>
# 1 01/1234  2013 PIZZA
# 2 01/1234  2014 PIZZA
# 3 01/1234  2015 PIZZA
# 4 05/1234  2013 PASTA
# 5 05/1234  2014 PASTA
# 6 05/1234  2015 PASTA

После этого мы используем левое соединение между исходным набором данных и этой таблицей поиска

Poging23 %>% 
  select(-Name) %>% 
  left_join(lookup, by = c("Code", "Year"))

Окончательный результат должен быть таким, как вы ожидаете

# A tibble: 16 x 5
#       ID Date_of_birth       Code     Year Name 
#    <dbl> <dttm>              <chr>   <dbl> <chr>
#  1     1 2000-05-25 00:00:00 01/1234  2013 PIZZA
#  2     1 2000-05-25 00:00:00 01/1234  2014 PIZZA
#  3     1 2000-05-25 00:00:00 01/1234  2015 PIZZA
#  4     1 2000-05-25 00:00:00 01/1234  2016 NA   
#  5     2 1970-10-21 00:00:00 01/1234  2013 PIZZA
#  6     2 1970-10-21 00:00:00 01/1234  2014 PIZZA
#  7     2 1970-10-21 00:00:00 01/1234  2015 PIZZA
#  8     2 1970-10-21 00:00:00 01/1234  2016 NA   
#  9     3 1978-10-22 00:00:00 01/1234  2013 PIZZA
# 10     3 1978-10-22 00:00:00 01/1234  2014 PIZZA
# 11     3 1978-10-22 00:00:00 05/1234  2015 PASTA
# 12     3 1978-10-22 00:00:00 05/1234  2016 NA   
# 13     4 2010-03-03 00:00:00 05/1234  2013 PASTA
# 14     4 2010-03-03 00:00:00 05/1234  2014 PASTA
# 15     4 2010-03-03 00:00:00 05/1234  2015 PASTA
# 16     4 2010-03-03 00:00:00 05/1234  2016 NA   

Если вы хотите избежать разделения процедуры на более мелкие шаги, просто объедините куски кода следующим образом:

library(tidyverse)

Poging23 %>% 
  select(-Name) %>% 
  left_join(Poging23 %>% 
              group_by(Code, Year) %>% 
              group_modify(~unique(.$Name) %>% enframe(name = NULL, value = "Name")) %>% 
              filter(Name != "NA"),
            by = c("Code", "Year"))
1 голос
/ 27 мая 2020

Функция агрегатного имени по коду и году покажет имена для каждой пары факторов. Для каждой пары вы можете увидеть, существует ли хотя бы одно имя

aggregate(Name ~ Year + Code, dfx, function(x) {x[x != "NA"]})
  Year    Code         Name
1 2013 01/1234        PIZZA
2 2014 01/1234 PIZZA, PIZZA
3 2015 01/1234        PIZZA
4 2016 01/1234             
5 2013 05/1234        PASTA
6 2014 05/1234        PASTA
7 2015 05/1234        PASTA
8 2016 05/1234             

Я предполагаю, что каждая пара Year, Code должна всегда иметь одно и то же имя (может повторяться, как в строке 2), и нужен только первый

uu <- aggregate(Name ~ Year + Code, dfx, function(x) {x[x != "NA"][1]})
> uu
  Year    Code  Name
1 2013 01/1234 PIZZA
2 2014 01/1234 PIZZA
3 2015 01/1234 PIZZA
4 2016 01/1234  <NA>
5 2013 05/1234 PASTA
6 2014 05/1234 PASTA
7 2015 05/1234 PASTA
8 2016 05/1234  <NA>

Затем для каждой строки из uu совпадающих строк в dfx соответствующее Имя может быть назначено из uu $ Name

for (i in 1:nrow(uu)) {
  dfx[
     dfx$Name=="NA" 
     & dfx$Code == uu[i, "Code"] 
     & dfx$Year == uu[i, "Year"] , "Name" ] <- uu[i, "Name"]
}
> dfx
   ID Date_of_birth    Code Year  Name
1   1    2000-05-25 01/1234 2013 PIZZA
2   1    2000-05-25 01/1234 2014 PIZZA
3   1    2000-05-25 01/1234 2015 PIZZA
4   1    2000-05-25 01/1234 2016  <NA>
5   2    1970-10-21 01/1234 2013 PIZZA
6   2    1970-10-21 01/1234 2014 PIZZA
7   2    1970-10-21 01/1234 2015 PIZZA
8   2    1970-10-21 01/1234 2016  <NA>
9   3    1978-10-22 01/1234 2013 PIZZA
10  3    1978-10-22 01/1234 2014 PIZZA
11  3    1978-10-22 05/1234 2015 PASTA
12  3    1978-10-22 05/1234 2016  <NA>
13  4    2010-03-03 05/1234 2013 PASTA
14  4    2010-03-03 05/1234 2014 PASTA
15  4    2010-03-03 05/1234 2015 PASTA
16  4    2010-03-03 05/1234 2016  <NA>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...