перекодировать несколько значений в совместно используемом столбце во многих фреймах данных с помощью переменной группировки - PullRequest
0 голосов
/ 27 января 2019

РЕДАКТИРОВАТЬ: я немного изменил репекс с исходного вопроса, потому что он не дал аналогичный пример для моего реального использования.

Это расширение предыдущего вопроса, перекодирование / замена нескольких значений в столбце общих данных на одно значение во всех фреймах данных , что прекрасно работает для более простого приложения. Я пытался, но безрезультатно, распространить решение на несколько более сложный случай. У меня есть много разных фреймов данных, каждый из которых имеет несколько общих столбцов («site» и «grp» в репексе ниже). В каждом из фреймов данных в переменной 'grp' есть несколько ошибок, некоторые из которых не являются общими. В предыдущем вопросе это было решено с использованием функций tidyverse и recode, путем создания list элементов ключ / значение и перекодирования их с помощью

keyval <- setNames(rep(good_values, lengths(bad_values)), unlist(bad_values))
out <- map(df_list, ~ .x %>% 
                  mutate(grp = recode_factor(grp, !!! keyval)))

Однако я хочу сделать это, когда список key / val зависит от значения другой разделяемой переменной, 'site'. Например, grp = a1 следует перекодировать в grp = a, когда site = s1, и grp = f, когда site = s2. Я попытался расширить приведенный выше код, используя map() с вложенным вызовом pmap() в следующем примере:

#example data frames
library(tidyverse)
df1 = data.frame(site = c(rep("s1",5), rep("s2",5), rep("s3",5)),grp = c("a1","a.","a.",rep("b",4),"b2","b-","bq",rep("a1",5)), measure = rnorm(15))

df2 = data.frame(site = c(rep("s1",10), rep("s2",16), rep("s3",5)), grp = c(rep("as", 3), "b2",rep("a",22),rep("a1",5)), measure2 = rnorm(31))

df3 = data.frame(site = c(rep("s1",3), rep("s2",6), rep("s3",5)),grp = c(rep("b-",3),rep("bq",2),"a", rep("a.", 3),rep("a1",5)), measure3 = 1:14)

df_list = list(df1, df2, df3)

site_list = c("s1","s2","s3")
bad_values = list(c("a1","a.","as", "b2", "b-", "bq"),
                  c("a1","a.","as","b", "b2", "b-", "bq"),
                  c("a1"))
good_values = list(c("a", "a1","a2","b","b1","b2"),
                   c("f","f1","f2","g","g","g1","g2"),
                   c("t"))
#put dfs into list to `map` over
df_list = list(df1, df2, df3)

#what I tried.
#nested pmap() within map()
dfs_mod = map(df_list, ~.x %>%
              pmap(list(site_list,bad_values,good_values),
                   ~mutate(.x, grp = ifelse(site == ..1,recode(grp, !!!setNames(as.list(..2),..3)),grp))))

В настоящее время выдается код ошибки «Ошибка: не знаю, как вырвать из языка». В поисках этой ошибки я не смог понять, что это за ошибка или как выполнить задачу.

РЕДАКТИРОВАТЬ: Я пытался также пытался

keyval = map2(good_values, bad_values, ~setNames(as.list(..1),unlist(..2)))
#this creates 3 lists of key/val elements to recode grp on for each site

dfs_mod = map(df_list, function(x){
  map2(site_list, keyval, ~mutate(x, grp = ifelse(site == ..1, recode_factor(grp, !!!..2), grp)))
})

Это не выдает ошибку, но не вполне выполняет то, что я желаю. У него есть пара нежелательных побочных эффектов: 1) он создает 3 списка по 3 кадра данных, по одному df, перекодированному для каждого из списков key / val, и 2) он перекодирует фактор 'grp' в целое число (что меня поражает). Становится все яснее, что я неправильно понимаю, что должен делать map*(), и не намерен его использовать. Поэтому любые другие способы итеративного достижения этого приветствуются.

Я предполагаю, что ожидаемый результат будет list такой же длины, что и df_list (3 в данном случае). Переменные 'grp' = 'bad_values' должны быть перекодированы в 'good_values' в зависимости от местоположения элемента списка и в зависимости от 'сайта' (например, bad_values ​​[[1]] [1] -> good_values ​​[[1]] [1 ], bad_values ​​[[1]] [2] -> good_values ​​[[1]] [2] и т. д. для site = site_list [[1]]). Первый кадр данных в 'dfs_mod' list должен выглядеть примерно так:

dfs_mod[[1]]

   site grp    measure
1    s1  a -1.2169476
2    s1  a1  1.0644877
3    s1  a1  0.2007733
4    s1   b  0.8613291
5    s1   b -0.3682463
6    s2   g  1.2535321
7    s2   g  0.7622614
8    s2   g  1.4022664
9    s2   g1 -0.8234464
10   s2   g2 -1.0000354 
11   s3   t  1.34320583
12   s3   t  1.33950010
13   s3   t -1.12670074
14   s3   t  1.59890652
15   s3   t  0.23932814

Спасибо за любую помощь.

#old repex data from original question that has been edited above
library(tidyverse)
#create example dfs
df1 = data.frame(site = c(rep("s1",5), rep("s2",5)),grp = c("a1","a.","a.",rep("b",4),"b2","b-","bq"), measure = rnorm(10))

df2 = data.frame(site = c(rep("s1",10), rep("s2",16)), grp = c(rep("as", 3), "b2",rep("a",22)), measure2 = rnorm(26))

df3 = data.frame(site = c(rep("s1",3), rep("s2",6)),grp = c(rep("b-",3),rep("bq",2),"a", rep("a.", 3)), measure3 = 1:9)

site_list = list("s1","s2")
bad_values = list(c("a1","a.","as", "b2", "b-", "bq"),
                   c("a1","a.","as","b", "b2", "b-", "bq"))
good_values = list(c("a", "a1","a2","b","b1","b2"),
                   c("f","f1","f2","g","g","g1","g2"))

1 Ответ

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

Я нашел способ выполнить эту задачу, который довольно быстро работает для моего использования с парой циклов for и использованием ответа на предыдущий (связанный) вопрос.Так просто, смущенно это заняло у меня столько времени

library(tidyverse)
keys = map2(good_values, bad_values, ~setNames(as.list(..1),unlist(..2)))

# how to accomplish
for(i in 1:length(site_list)){
  for(df in 1:length(df_list)){
    df_list[[df]] <- pluck(df_list, df) %>%
      mutate(grp = if_else(site == pluck(site_list,i), recode(grp, !!!pluck(keys,i)),grp))
  }
}

df_list[[1]]
   site grp     measure
1    s1   a  0.60083152
2    s1  a1 -0.56181835
3    s1  a1  1.31789556
4    s1   b -2.06659322
5    s1   b  1.21575623
6    s2   g -1.05263188
7    s2   g  1.68731655
8    s2   g -0.59827489
9    s2  g1 -2.22322604
10   s2  g2  0.22577945
11   s3   t -0.08614122
12   s3   t  0.74511934
13   s3   t  1.29782596
14   s3   t -1.87684060
15   s3   t -0.90672568
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...