R: заполнить data.frame внутри функции в mapply - PullRequest
1 голос
/ 20 июня 2020

Запрашивается data.frame df1 (нечеткое совпадение) с другим data.frame df2 с agrep. Посредством итерации по его выходным данным (список с именем matches, содержащий номер строки соответствующих совпадений в df2), df1 заполняется аффилированными значениями из df2. Цель - это функция, которая передается в mapply; однако во всех моих попытках df1 остается неизменным.

В for-l oop код работает должным образом и заполняет df1 аффилированными переменными из df2. Тем не менее, мне было бы интересно, как решить эту проблему с помощью функции, которая передается в mapply.

Сначала два data.frames:

df1 <- structure(list(Species = c("Alisma plantago-aquatica", "Alnus glutinosa",
                                  "Carex davalliana", "Carex echinata",
                                  "Carex elata"),
                      CheckPoint = c(NA, NA, NA, NA, NA),
                      L = c(NA, NA, NA, NA, NA),
                      R = c(NA, NA, NA, NA, NA),
                      K = c(NA, NA, NA, NA, NA)),
                 row.names = c(NA, 5L), class = "data.frame")

df2 <- structure(list(Species = c("Alisma gramineum", "Alisma lanceolatum",
                                  "Alisma plantago-aquatica", "Alnus glutinosa",
                                  "Alnus incana", "Alnus viridis",
                                  "Carex davalliana", "Carex depauperata",
                                  "Carex diandra", "Carex digitata",
                                  "Carex dioica", "Carex distans",
                                  "Carex disticha", "Carex echinata",
                                  "Carex elata"),
                      L = c(7L, 7L, 7L, 5L, 6L, 7L, 9L, 4L, 8L, 3L, 9L, 9L, 8L,
                            8L, 8L),
                      R = c(7L, 7L, 5L, 5L, 4L, 3L, 4L, 7L, 6L, NA, 4L, 6L, 6L,
                            NA, NA),
                      K = c(6L, 2L, NA, 3L, 5L, 4L, 4L, 2L, 7L, 4L, NA, 3L, NA,
                            3L, 2L)),
                 row.names = seq(1:15), class = "data.frame")

Затем нечеткое совпадение Species:

matches <- lapply(df1$Species, agrep, x = df2$Species, value = FALSE,
                 max.distance = c(deletions = 0,
                                  insertions = 1,
                                  substitutions = 1))

Заполнение df1 значениями из df2 работает должным образом:

for (i in 1:dim(df1)[1]){
  df1[i, 2:5] <- df2[matches[[i]], ]
  }

В отличие от моего подхода с mapply, который действительно возвращает правильный values, хотя и как список разобранных значений, которые никогда не записываются в df1. Никакая комбинация (с return(df1) или без, запись его в другую переменную или отдельные попытки с состоянием SIMPLIFY или USE.NAMES) не дала желаемых результатов.

populatedf1 <- function(matches, index){
    df1[index, 2:5] <- df2[matches, ]
  #return(df1)
  }

mapply(populatedf1, matches, seq_along(matches), SIMPLIFY = FALSE,
              USE.NAMES = FALSE)

Было бы здорово, если бы кто-нибудь знал решение или может указать мне определенное направление, спасибо! :)

1 Ответ

3 голосов
/ 20 июня 2020

На самом деле, вам не понадобится здесь l oop (for или mapply), если вы замените lapply на sapply (чтобы он возвращал вектор вместо списка), а затем выполните прямое присвоение.

matches <- sapply(df1$Species, agrep, x = df2$Species, value = FALSE,
                   max.distance = c(deletions = 0,
                                    insertions = 1,
                                   substitutions = 1))

df1[, 2:5] <- df2[matches,]
df1

#                   Species               CheckPoint L  R  K
#1 Alisma plantago-aquatica Alisma plantago-aquatica 7  5 NA
#2          Alnus glutinosa          Alnus glutinosa 5  5  3
#3         Carex davalliana         Carex davalliana 9  4  4
#4           Carex echinata           Carex echinata 8 NA  3
#5              Carex elata              Carex elata 8 NA  2

Что касается вашего подхода, вы можете использовать Map или mapply с SIMPLIFY = FALSE и перенести список фреймов данных в один фрейм данных, используя do.call и rbind, а затем назначить.

df1[, 2:5] <- do.call(rbind, Map(populatedf1, matches, seq_along(matches)))
...