【问题标题】:Can I ask R to identify the name of a data frame and then add that name to a column in the same data frame?我可以要求 R 识别数据框的名称,然后将该名称添加到同一数据框中的列中吗?
【发布时间】:2021-05-18 20:48:41
【问题描述】:

提前致歉,但我在这里和 R 都是新手。我想做的是 自动 在数据框中添加一列,其中填充了实际名称数据框。例如,如果我有以下数据框:

> q103
  a  b  c  d
d 1  4  6  9
e 2  8  3  12
f 3 12  8  16

如何在每行中添加一个包含字符串 q103 的列的末尾(没有具体命名它,因为我需要对数百个数据帧重复此操作),这样我就结束了与:

> q103
  a  b  c  d  X
d 1  4  6  9 q103
e 2  8  3 12 q103
f 3 12  8 16 q103

问题是这些数据框有很多,并且它们在列表列表中(例如,像 List[[list]][["q100277']] 是一个数据列表中的框架)。此外,它们的名称有些随机,但保留很重要(我不能只是按顺序重命名它们)。所以,我需要一种方法来告诉 R 基本上“查看数据框 X 的名称并将该字符串添加到数据框中的新列中,然后对列表中的每个数据框执行此操作”)。感觉某种 lapply 会起作用,但我不知道实际告诉它要做什么为了到达那里。

非常感谢您在弄清楚如何将一列放入每个数据帧中的任何帮助

编辑:我尝试在下面创建一个可重现的示例(每个 cmets)。这将创建类似于我正在查看的内容(除了示例是一个小得多的列表!)

library(CTT)
library(dplyr)
library(tidyverse)
library(purrr)

## Create student response patterns for a fake test

q102 <- c("A", "B", "C", "D", "O", "A", "A", "C", "D", "A", "C", "D", "O", "D", "A", "B", "A", "C", "D", "A")
q107 <- c("C", "D", "O", "D", "A", "B", "A", "C", "D", "A", "A", "B", "C", "D", "O", "A", "A", "C", "D", "A")
q1045 <- c("B", "O", "C", "A", "D", "B", "O", "C", "A", "D", "B", "O", "C", "A", "D", "B", "O", "C", "A", "D")
q101 <- c("A", "B", "C", "D", "O", "A", "A", "C", "D", "A", "B", "O", "C", "A", "D", "B", "O", "C", "A", "D")
q1064 <- c("C", "D", "O", "D", "A", "B", "A", "C", "D", "A", "A", "B", "C", "D", "O", "A", "A", "C", "D", "A")
q104 <- c("A", "B", "C", "D", "O", "A", "A", "C", "D", "A", "B", "O", "C", "A", "D", "B", "O", "C", "A", "D")

## Create an assessment key to identify the test
AssessmentKey <- c("ADW", "ADW", "ADW", "ADW", "ADW", "ADW", "ADW", "ADW", "ADW", "ADW", "ADW", "ADW", "ADW", "ADW", "ADW", "ADW", "ADW", "ADW", "ADW", "ADW")

## Assign response pattern to the assessment key
Students1 <- data.frame(q102, q107, q1045, q101, q1064, q104, AssessmentKey)
remove(AssessmentKey)

## Create a second assessment key to identify a different test
AssessmentKey <- c("XYZ", "XYZ", "XYZ", "XYZ", "XYZ", "XYZ", "XYZ", "XYZ", "XYZ", "XYZ", "XYZ", "XYZ", "XYZ", "XYZ", "XYZ", "XYZ", "XYZ", "XYZ", "XYZ", "XYZ")

## Assign the response pattern to the second assessment key
Students2 <- data.frame(q102, q107, q1045, q101, q1064, q104, AssessmentKey)
remove(q102, q107, q1045, q101, q1064, q104, AssessmentKey)
## Create a data frame combining the two different assessments
StudentAnswers <- rbind(Students1, Students2)

## Create a data frame with the answer key for both tests
AnswerKey <- c("A", "B", "A", "A", "C", "D", "A", "B", "A", "A", "C", "D")
QuestionKey <- c("q102", "q107", "q1045", "q101", "q1064", "q104",
                 "q102", "q107", "q1045", "q101", "q1064", "q104")
AssessmentKey <- c("ADW", "ADW", "ADW", "ADW", "ADW", "ADW", "XYZ", "XYZ", "XYZ", "XYZ", "XYZ", "XYZ")
AnswerKeys <- data.frame(QuestionKey, AnswerKey, AssessmentKey)
remove(AnswerKey, QuestionKey, AssessmentKey)



X <- c("ADW", "XYZ")
y <- lapply(
  (X), function(x) 
  {
    ## This will filter the data file to a specific assessment and 
    ## select the columns needed for analysis
    StudentResponse <- StudentAnswers %>%
      dplyr::filter(AssessmentKey == x) %>%
      dplyr::select(q102, q107, q1045, q101, q1064, q104)
  
      
      AKey <- AnswerKeys %>%
        dplyr::filter(AssessmentKey == x) %>%
        dplyr::select(AnswerKey)

      ## using safely from the purr package to run the distractorAnalyis
      ## function from CTT in case of errors

      safeDA = safely(.f=distractorAnalysis)
      safeDA(StudentResponse, AKey)
      
      
    }
)

## This part removes the empty "error" data frames from the list generated above.
Z <- c(1:length(y))
Results <- lapply(
  (Z), function(Z)
  {  y[[Z]][["result"]]
    
  })
  

【问题讨论】:

  • 你能提供一个小的reproducible example吗?具体来说,这将有助于了解数据帧是否处于不同的深度以及它们的深度。像 imappurrr 这样的函数可以轻松地遍历列表的名称及其内容,但具体如何调用它取决于嵌套列表的设置。
  • 您的数据是否类似于 a &lt;- head(mtcars); list(list(name1=a, name2=a)) ?一个例子可以是非常简单的,告诉我们如何回答你的问题。
  • 用一个示例更新了帖子,该示例将生成与我正在使用的列表类似的列表(尽管长度更短)

标签: r list dataframe


【解决方案1】:

如果我的解释正确,您希望在列表中查找所有数据框并添加一个具有该元素名称的列。

您可以结合使用rlang::squashpurrr::map2 函数来完成此操作。

  1. squash 将递归地将您的列表扁平化为 dataframes 的单个列表。
  2. 然后,您可以映射每个元素并添加一个带有列表元素名称的列。

我提供了一种从列表中删除层次结构的解决方案,并且您可以在其中维护列表的结构。

my_list <- list(
  q0 = mtcars,
  sub_list_1 = list(
      q1 = mtcars
    , q2 = mtcars
  )
  , sub_list_2 = list(
      sub_sub_list_1 = list(
        q3 = mtcars,
        q4 = mtcars
      )
      , sub_sub_list_2 = list(
        q5 = mtcars,
        q6 = mtcars
      )
  )
)
# function to add name col
add_col <- function(table, name) {
  if(!is.data.frame(table)) return(table) # If not a dataframe just return
  
  table$X <- name # add column
  
  return(table)
}

解决方案 1

# Using pipes (%>%), purrr, rlang
library(rlang)
library(purrr)

my_list %>% 
  squash() %>% 
  map2(names(.), add_col)

# Using rlang and base R
flat_list <- squash(my_list)
mapply(add_col, flat_list, names(flat_list), SIMPLIFY = F)

如果你想维护列表的结构,你可以递归地遍历并应用我们的add_col函数

解决方案 2

library(purrr)
library(rlang)

recursive_add_col <- function(x) {
  map2(x, names(x), 
      function(x, y) if(is.list(x) & !is.data.frame(x)) recursive_add_col(x) else add_col(x, y)
      )
}

my_list %>% 
  recursive_add_col()

【讨论】:

  • 谢谢!这非常有效。我还没有走出困境,但我肯定比现在走得更远。
【解决方案2】:

如果我理解正确,您想提取一些(嵌套)列表成员的名称,然后将一列分配到该列表成员中包含的数据框中。

这是一个使用示例数据的快速而肮脏的解决方案。这不是最佳实践,但它会很快完成。请注意 &lt;&lt;- 向上移动各种环境级别,直到在全局环境中找到列表。

# Example data
data(mtcars)

first_list <- list()
first_list[["item1"]] <- list()
first_list[["item2"]] <- list()
first_list[["item1"]][["level2_item1"]] <- mtcars
first_list[["item1"]][["level2_item2"]] <- mtcars

# Iterate through the names of "item1", look up the corresponding dataframe, add a column

lapply(
  names(first_list[["item1"]]),
  function(x) {
    first_list[["item1"]][[x]]$NewCol <<- x
  }
)

【讨论】:

    猜你喜欢
    • 2020-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-31
    • 1970-01-01
    • 1970-01-01
    • 2019-01-10
    相关资源
    最近更新 更多