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

Я надеюсь, что не пропустил это, но я не смог найти работающего решения этой проблемы. У меня есть набор фреймов данных с общим столбцом. Эти столбцы содержат несколько и разные ошибки транскрипции, некоторые из которых являются общими, а другие нет, для нескольких значений. Я хотел бы заменить / перекодировать ошибки транскрипции (bad_values) с правильными значениями (good_values) во всех фреймах данных.

Я попытался вложить семейство функций map*() в списки фреймов данных, bad_values ​​и good_values, чтобы сделать это, среди прочего. Вот пример:

df1 = data.frame(grp = c("a1","a.","a.",rep("b",7)), measure = rnorm(10))

df2 = data.frame(grp = c(rep("as", 3), "b2",rep("a",22)), measure = rnorm(26))

df3 = data.frame(grp = c(rep("b-",3),rep("bq",2),"a", rep("a.", 3)), measure = 1:9)


df_list = list(df1, df2, df3)
bad_values = list(c("a1","a.","as"), c("b2","b-","bq"))
good_values = list("a", "b")

dfs = map(df_list, function(x) {
  x %>% mutate(grp = plyr::mapvalues(grp, bad_values, rep(good_values,length(bad_values))))
})

То, что я не обязательно ожидал, будет работать за пределами одной пары хорошее-плохое значение. Тем не менее, я подумал, что в этом случае может сработать еще один вызов map*():

dfs = map(df_list, function(x) {
x %>% mutate(grp = map2(bad_values, good_values, function(x,y) {
recode(grp, bad_values = good_values)})
})

Я пробовал ряд других подходов, ни один из которых не сработал.

В конечном счете, я хотел бы перейти от набора фреймов данных с ошибками, как здесь:

[[1]]
  grp    measure
1  a1  0.5582253
2  a.  0.3400904
3  a. -0.2200824
4   b -0.7287385
5   b -0.2128275
6   b  1.9030766

[[2]]
  grp    measure
1  as  1.6148772
2  as  0.1090853
3  as -1.3714180
4  b2 -0.1606979
5   a  1.1726395
6   a -0.3201150

[[3]]
  grp measure
1  b-       1
2  b-       2
3  b-       3
4  bq       4
5  bq       5
6   a       6

К списку «фиксированных» фреймов данных, например:

[[1]]
  grp    measure
1   a -0.7671052
2   a  0.1781247
3   a -0.7565773
4   b -0.3606900
5   b  1.9264804
6   b  0.9506608

[[2]]
  grp     measure
1   a  1.45036125
2   a -2.16715639
3   a  0.80105611
4   b  0.24216723
5   a  1.33089426
6   a -0.08388404

[[3]]
  grp measure
1   b       1
2   b       2
3   b       3
4   b       4
5   b       5
6   a       6

Любая помощь будет очень ценится

Ответы [ 3 ]

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

Базовая опция R, если у вас много good_values и bad_values, и вы не можете проверить каждый из них по отдельности.

lapply(df_list, function(x) {
  vec = x[['grp']]
  mapply(function(p, q) vec[vec %in% p] <<- q ,bad_values, good_values)
  transform(x, grp = vec)
})


#[[1]]
#   grp      measure
#1    a -0.648146527
#2    a -0.004722549
#3    a -0.943451194
#4    b -0.709509396
#5    b -0.719434286
#....

#[[2]]
#   grp     measure
#1    a  1.03131291
#2    a -0.85558910
#3    a -0.05933911
#4    b  0.67812934
#5    a  3.23854093
#6    a  1.31688645
#7    a  1.87464048
#8    a  0.90100179
#....

#[[3]]
#  grp measure
#1   b       1
#2   b       2
#3   b       3
#4   b       4
#5   b       5
#....

Здесь для каждого элемента списка мы извлекаем его столбец grp и заменяем bad_values на соответствующий good_values, если они найдены, и возвращают исправленный кадр данных.

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

Здесь можно использовать tidyverse с recode_factor.Если необходимо изменить несколько элементов, создайте list элементов key / val и используйте recode_factor для сопоставления и изменения значений на новые levels

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

-output

out
#[[1]]
#   grp     measure
#1    a -1.63295876
#2    a  0.03859976
#3    a -0.46541610
#4    b -0.72356671
#5    b -1.11552841
#6    b  0.99352861
#....

#[[2]]
#   grp     measure
#1    a  1.26536789
#2    a -0.48189740
#3    a  0.23041056
#4    b -1.01324689
#5    a -1.41586086
#6    a  0.59026463
#....


#[[3]]
#  grp measure
#1   b       1
#2   b       2
#3   b       3
#4   b       4
#5   b       5
#6   a       6
#....

ПРИМЕЧАНИЕ. Это не меняет class исходного столбца набора данных

str(out)
#List of 3
# $ :'data.frame':  10 obs. of  2 variables:
#  ..$ grp    : Factor w/ 2 levels "a","b": 1 1 1 2 2 2 2 2 2 2
#  ..$ measure: num [1:10] -1.633 0.0386 -0.4654 -0.7236 -1.1155 ...
# $ :'data.frame':  26 obs. of  2 variables:
#  ..$ grp    : Factor w/ 2 levels "a","b": 1 1 1 2 1 1 1 1 1 1 ...
#  ..$ measure: num [1:26] 1.265 -0.482 0.23 -1.013 -1.416 ...
# $ :'data.frame':  9 obs. of  2 variables:
#  ..$ grp    : Factor w/ 2 levels "a","b": 2 2 2 2 2 1 1 1 1
#  ..$ measure: int [1:9] 1 2 3 4 5 6 7 8 9

Если у нас есть пара ключей-ключей list, это также можно использовать в base R функций

out1 <- lapply(df_list, transform, grp = unlist(keyval[grp]))
0 голосов
/ 03 января 2019

По какой-либо причине отображение оператора case_when не сработает?

library(tidyverse)
df_list %>% 
  map(~ mutate_if(.x, is.factor, as.character)) %>% # convert factor to character
  map(~ mutate(.x, grp = case_when(grp %in% bad_values[[1]] ~ good_values[[1]],
                                   grp %in% bad_values[[2]] ~ good_values[[2]],
                                   TRUE ~ grp)))

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

...