Как вставить символьную переменную в функцию lapply?

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

Я создал следующий образец даты, чтобы проиллюстрировать проблему.

data <- data.frame(
words1 = c("apple", "pear", "banana", "pear", "banana"),
words2 = c("pear", "banana", "pear", "banana", "cherry"),
words3 = c("banana", "ananas", "apple", "melon", "pear"),
value1 = c(2, 1, 2, 0, 1),
value2 = c(2, 0, 0, 2, 0),
value3 = c(0, 2, 2, 1, 1)
)
allwords <- c("apple", "pear", "banana", "ananas", "melon", "cherry")
attach(data)
  • words[1:3] — векторы символов, содержащие слова, некоторые слова упоминаются многими участниками, другие — только одним участником. Каждый участник может упомянуть определенное слово один раз и не более.
  • value[1:3] — числовые векторы, содержащие числа от 0 до 2.
  • allwords — это отдельный вектор, содержащий все слова, встречающиеся в word[1:3].
head(data)
  words1 words2 words3 value1 value2 value3
1  apple   pear banana      2      2      0
2   pear banana ananas      1      0      2
3 banana   pear  apple      2      0      2
4   pear banana  melon      0      2      1
5 banana cherry   pear      1      0      1

Я хочу создать набор векторов, каждый из которых посвящен одному из слов во всех словах, сообщая значение, которое каждый участник присвоил этому слову (NA, если значение не назначено). Это результат, который я пытаюсь получить:

apple pear banana ananas melon cherry
2     2    0      NA     NA      NA
NA    1    0      2      NA      NA 
2     0    2      NA     NA      NA
NA    0    2      NA     1       NA
NA    1    1      NA     NA      0

Я написал эту функцию для достижения этой цели

value.f <- function(y){
  values.w[[y]] <- NA
  value.var <- values.w[[y]]
  value.var[which(data$words1 == y)] <- data$value1
  value.var[which(data$words2 == y)] <- data$value2
  value.var[which(data$words3 == y)] <- data$value3
}
values.w <- list()
values.w <- lapply(allwords, value.f)
names(values.w)  <- c(allwords)

Но для каждого слова я получаю содержимое data$value3. В принципе все "какие" условия признаны верными, но я не понимаю почему.

as.data.frame(values.w)

apple pear banana ananas melon cherry
0     0     0     0     0      0     
2     2     2     2     2      2 
2     2     2     2     2      2     
1     1     1     1     1      1     
1     1     1     1     1      1     

Я не понимаю, что делаю не так, но мне очень трудно использовать векторы символов в функциях lapply(), поэтому я предполагаю, что у меня возникла такая проблема.

Я пробовал с eval(parse(text=y), пробовал с paste0(y), но ничего из этого не работает.

Я не понимаю. Просто заменить 0 на NA?

Friede 13.08.2024 12:55
names(data) предполагает, что имена data.frame не такие, как вы ожидаете. Замените назначение <-, используемое при построении фрейма данных, на =, например. г. words1 = ... вместо words1 <- ... и ваш код должен работать.
I_O 13.08.2024 13:09

@I_O Спасибо, это была небольшая ошибка с моей стороны. Я исправил это в вопросе. Конечно, это не имеет ничего общего с функцией, которая все еще не дает ожидаемого результата.

Silvia 13.08.2024 13:14

@Friede К сожалению, это не имеет ничего общего с заменой 0 на NA. Я пытаюсь создать новые столбцы, по одному для каждого слова. Я попытался объяснить проблему лучше в своем вопросе.

Silvia 13.08.2024 13:18

@Сильвия: Я добавила рабочую версию вашей первоначальной попытки в конце своего ответа. Проблемы были не с векторами символов или lapply.

I_O 13.08.2024 14:43
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
5
52
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Одна возможность. Он использует {dplyr}, у которого есть функция bind_rows, которая может связывать строки данных с различным составом переменных, не жалуясь на то, что переменные не совпадают (как это было бы rbind).

  • ваш пример данных:
##   words1 words2 words3 value1 value2 value3
## 1  apple   pear banana      2      2      0
## 2   pear banana ananas      1      0      2
## 3 banana   pear  apple      2      0      2
## 4   pear banana  melon      0      2      1
## 5 banana cherry   pear      1      0      1
  • это вспомогательная функция, которая принимает строку фрейма данных и преобразует ее в именованный список (а именно однострочный фрейм данных), рассматривая первые itemcount элементы как имена (столбцов), а вторые itemcount элементы как значения:
    row_to_named_list <- \(row, itemcount = 3){
      setNames(row[1:itemcount + itemcount],
               row[1:itemcount]
      )
    }
  • здесь мы используем do.call для вызова функции (bind_rows) в списке (однострочных фреймов данных, возвращаемых lapplyвышеуказанной вспомогательной функцией с индексами строк 1:5):
    library(dplyr)

    do.call(dplyr::bind_rows,
          lapply(1:5, \(r) row_to_named_list(data[r, ]))
    )

выход:

##   apple pear banana ananas melon cherry
## 1     2    2      0     NA    NA     NA
## 2    NA    1      0      2    NA     NA
## 3     2    0      2     NA    NA     NA
## 4    NA    0      2     NA     1     NA
## 5    NA    1      1     NA    NA      0

редактировать

Ниже приведена адаптированная версия вашей функции, которая работает должным образом. Основными ошибками были невозможность вернуть результат функции и перезапись value.var в неправильных позициях, value3 переопределяя предыдущие замены.

value.f <- function(y){
  ## `<-` can't change objects outside the function from within
  ## the function anyway:
  ## values.w[[y]] <- NA
  ## this would create a single-item value.var containing only NA
  ## value.var <- values.w[[y]]
  value.var <- rep(NA, 5) ## instantiate value.var as an NA-vector of desired length
  ## replacement values must have same length as replacement positions:
  value.var[which(data$words1 == y)] <- data$value1[which(data$words1 == y)]
  value.var[which(data$words2 == y)] <- data$value2[which(data$words2 == y)]
  value.var[which(data$words3 == y)] <- data$value3[which(data$words3 == y)]
  ## don't forget to return value.var!
  value.var
}

## values.w <- list() # lapply returns a list anyway
values.w <- lapply(allwords, value.f2)
names(values.w)  <- c(allwords)

list2DF(values.w) ## make this a dataframe

Спасибо и за объяснение!

Silvia 13.08.2024 14:58

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

library(data.table)
setDT(data)

#create index column
data[, id := .I]

#transform to long format
DT <- melt(data,  measure.vars = patterns(word = "^word", value = "^value"))

#join
DT <- DT[#all possible combinations of ids and words:
         CJ(word = allwords, id = unique(DT[["id"]])), 
         #which columns to join on:
         on = c("word", "id")]

#transform to wide format
dcast(DT, id ~ word, value.var = "value")
# Key: <id>
#       id ananas apple banana cherry melon  pear
#    <int>  <num> <num>  <num>  <num> <num> <num>
# 1:     1     NA     2      0     NA    NA     2
# 2:     2      2    NA      0     NA    NA     1
# 3:     3     NA     2      2     NA    NA     0
# 4:     4     NA    NA      2     NA     1     0
# 5:     5     NA    NA      1      0    NA     1

В ожидаемом результате было несколько опечаток, спасибо, что заметили их!

Silvia 13.08.2024 14:58

@Silvia Я не думаю, что это опечатки, но порядок столбцов отличается от ожидаемого результата в вопросе.

ThomasIsCoding 13.08.2024 17:27

Другие вопросы по теме