使用 R expss 和 data.table 是不是可以从 csv 文件加载 data.table 标签,而不是手动输入代码?

Posted

技术标签:

【中文标题】使用 R expss 和 data.table 是不是可以从 csv 文件加载 data.table 标签,而不是手动输入代码?【英文标题】:Using R expss and data.table is it possible to load data.table labels from a csv file instead of typing the code in by hand?使用 R expss 和 data.table 是否可以从 csv 文件加载 data.table 标签,而不是手动输入代码? 【发布时间】:2020-09-14 00:32:30 【问题描述】:

应用标签是使调查数据在报告时易于理解的重要部分

所以我能找到的最好的例子是使用 expss::apply_labels() 例如著名的 mtcars 示例 https://cran.r-project.org/web/packages/expss/vignettes/tables-with-labels.html

作为输入,这需要一个 data.table 和一个逗号分隔的赋值对列表,例如

apply_labels(dt, col1 = "label1", col2 = "label2", col3 = "label3")

如果您有一个数据文件和几列,这很好,每次都输入它们会很麻烦,但如果您有很多数据文件,它就不是很有帮助。那么如何加载 csv 元数据文件 格式:

Col1 Col2 Col3

标签1 标签2 标签3

其中 Col 名称与数据表中的相同名称匹配

这意味着有效地翻译元数据 csv 文件以便生成

coln = "标签n"

对于每一列。

到目前为止,我发现最大的问题是应用标签列名是对象而不是字符串,并且很难将字符串转换为正确范围内的对象。

这是我要去的地方

    library(expss)
    library(data.table)
    library(glue)

    readcsvdata <- function(dfile)
     
        rdata <- fread(file = dfile, sep = "," , quote = "\"" , header = TRUE, 
        stringsAsFactors = FALSE, na.strings = getOption("datatable.na.strings","NA"))
        return(rdata)
        

    rawdatafilename <- "testdata.csv"
    rawmetadata <- "metadata.csv"

    mdt <- readcsvdata(rawmetadata)
    rdt <-readcsvdata(rawdatafilename)
    commonnames <- intersect(names(mdt),names(rdt))  # find common 
    qlabels <- as.character(mdt[1, commonnames, with = FALSE])

    comslist <- list()
    for (i in 1:length(commonnames)) # loop through commonnames and qlabels
            
          if (i == length(commonnames))
              x <- glue('commonnames[i] = "qlabels[i]"') # no comma for final item
              else 
              x <- glue('commonnames[i] = "qlabels[i]",') # comma for next item

          comslist[[i]] <- x
    

comstring <- paste(unlist(comslist), collapse = '')

tdt = apply_labels(tdt, eval(parse(text = comstring)))

产生

解析错误(text = comstring) : :1:24: unexpected ',' 1: varone = "Label1", ^

哦,print(comstring) 产生:

[1] "varone = \"问题一\",vartwo = \"问题二\",varthree = \"问题三\",varfour = \"问题四\",varfive = \"问题 五\",varsix = \"问题六\",varseven = \"问题 七\",vareight = \"问题八\",varnine = \"问题 九\",varten = \"问题十\""

【问题讨论】:

如果这确实是一个 CSV 文件,并且您使用 read.csv(或 fread 或其他)读取它,那么 do.call(apply_labels, c(list(dt), csvdat)) 应该可以工作。 您可以在循环中使用var_labfor(each in colnames(metadata)) var_lab(dt[[each]]) = metadata[[each]] 【参考方案1】:

apply_labels 对于来自外部字典的赋值标签不是很方便。您可以改用var_lab

library(expss)
library(data.table)

readcsvdata <- function(dfile)

    rdata <- fread(file = dfile, sep = "," , quote = "\"" , header = TRUE, 
                   stringsAsFactors = FALSE, na.strings = getOption("datatable.na.strings","NA"))
    return(rdata)


rawdatafilename <- "testdata.csv"
rawmetadata <- "metadata.csv"

mdt <- readcsvdata(rawmetadata)
rdt <-readcsvdata(rawdatafilename)
commonnames <- intersect(names(mdt),names(rdt))  # find common 
qlabels <- as.list(mdt[1, commonnames, with = FALSE])


for (each_name in commonnames) # loop through commonnames and qlabels
  
    var_lab(rdt[[each_name]]) <- qlabels[[each_name]]

值标签有一个类似的val_lab 函数。此外,您可能对apply_dictionarycreate_dictionary 函数感兴趣。要获得有关他们的帮助,请在控制台中键入 ?apply_dictionary

【讨论】:

非常感谢。小点但是 var_lab(rdt[[each_name]]) = qlabels[[each_name]] 不起作用 var_lab(rdt[[each_name]]) @PeterKing 感谢您的报告。我编辑了答案。但真的很奇怪——在这种情况下应该没有区别。【参考方案2】:

我没有方便的expss,但我认为这通常是关于如何以编程方式在 R 中分配函数参数。

如果您从包含您需要的三个配对的 CSV 文件开始,

csvdat <- read.csv(stringsAsFactors=FALSE, text="
col1,col2,col3
label1,label2,label3")

我将编写一个伪函数(因为我没有expss,这并不重要),它动态接受第一个参数和零个或多个后续参数。

my_fake_labels <- function(x, ...) 
  dots <- list(...)
  message("x labels   : ", paste(sQuote(colnames(x)), collapse = ", "))
  message("other names: ", paste(sQuote(names(dots)), collapse = ", "))

origDT <- data.table(aa=1, bb=2)

my_fake_labels(origDT, col1="label1", col2="label2", col3="label3")
# x labels   : 'aa', 'bb'
# other names: 'col1', 'col2', 'col3'

这是您要避免的手动参数设置。 (我知道我在这里没有做任何标签设置,让我们暂时忽略它。)

执行此操作的编程方式,使用origDT 作为第一个参数,csvdat 的元素作为第二个和后续参数:

do.call(my_fake_labels, c(list(origDT), csvdat))
# x labels   : 'aa', 'bb'
# other names: 'col1', 'col2', 'col3'

do.call 的第二个参数必须是 list,可以选择命名。由于 data.frame(因此是 data.table)只是一个名为 list 的美化名称,因此符合要求。它的作用是获取列表中的每个元素并将其应用为函数的相应参数(do.call 的第一个参数)。

list(origDT) 是因为通常c(...) 函数会连接两个列表的列/元素。如果我们只执行c(origDT, csvdat),那么函数将使用ncol(origDT) + ncol(csvdat) 参数调用,而不是所需的1 + ncol(csvdat)。为此,c(list(origDT), ...) 确保整个 origDT 是函数的第一个参数。

(以编程方式形成csvdat 也可能很容易,而不需要外部文件,但我猜你有理由通过 CSV 来实现。)

【讨论】:

这可能很复杂,但恐怕我根本不明白。我看不到您的功能 my_fake_labels 是做什么用的。为了争论,它是 expss apply_labels 的代理吗?什么是列表(...)?请原谅一个苦苦挣扎的初学者。 “我会写一个假函数(因为我没有expss)”。添加到那个“这个假函数采用与你的apply_labels相同的参数,所以只要我们需要它,它的行为就类似于这里”。只需将其替换为您的 expss::apply_labels,然后看看会发生什么。 list(...) 是 R 的(重新)打包任意(0 或更多)长度参数的方式。 试过 do.call 添加第一个参数(数据表的名称) tdt 我认为purrr::prepend 正在从您的comslist 中剥离课程,所以expss::apply_labels 不知道如何处理它。我不知道您为什么要在列表中预先添加文字字符串 "tdt",但这似乎很奇怪。你就不能do.call(apply_labels, c(tdt, comslist))吗?

以上是关于使用 R expss 和 data.table 是不是可以从 csv 文件加载 data.table 标签,而不是手动输入代码?的主要内容,如果未能解决你的问题,请参考以下文章

使用 expss 在 R Marksdown 中格式化表格

在R中的嵌套变量中具有行百分比的expss表

R expss use_labels 和 dplyr 逻辑

如何在循环内正确解析expss中的(?)mdset?

R中的条件交叉表

如何防止 R Expss 在输出数据框中将变量名称与行标签混合?