使用 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_lab
:for(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_dictionary
和create_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 标签,而不是手动输入代码?的主要内容,如果未能解决你的问题,请参考以下文章