Можно ли с помощью R expss и data.table загружать метки data.table из файла csv вместо того, чтобы вводить код вручную?

Наклеивание ярлыков - важная часть обеспечения понятности данных опроса при представлении.

Итак, лучший пример, который я могу найти, использует expss :: apply_labels (), например, знаменитый пример mtcars https://cran.r-project.org/web/packages/expss/vignettes/tables-with-labels.html

в качестве ввода для этого требуется таблица данных и список пар присваиваний, разделенных запятыми, например

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

Это нормально, если у вас есть один файл данных и несколько столбцов, и вы можете беспокоиться, вводя их каждый раз, но это не очень полезно, если у вас много файлов данных. Итак, как можно загрузить файл метаданных csv в формате:

Col1 Col2 Col3

Этикетка1 Этикетка2 Этикетка3

где имена Col соответствуют тем же именам в таблице данных

это означает эффективный перевод CSV-файла метаданных так, чтобы он генерировал

col n = "label 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: неожиданно ',' 1: varone = "Label1", ^

ой и print (comstring) производит:

[1] "varone = \" Вопрос один \ ", vartwo = \" Вопрос два \ ", varthree = \" Вопрос три \ ", varfour = \" Вопрос четыре \ ", varfive = \" Вопрос пять \ ", varsix = \ "Вопрос шесть \", varseven = \ "Вопрос семь \", vareight = \ "Вопрос восемь \", varnine = \ "Вопрос девять \", varten = \ "Вопрос десять \" »


person Peter King    schedule 27.05.2020    source источник
comment
Если это действительно файл CSV, и вы читаете его с помощью read.csv (или fread или как-то еще), тогда do.call(apply_labels, c(list(dt), csvdat)) должен работать.   -  person r2evans    schedule 27.05.2020
comment
Вы можете использовать var_lab в цикле: for(each in colnames(metadata)) var_lab(dt[[each]]) = metadata[[each]]   -  person Gregory Demin    schedule 27.05.2020


Ответы (2)


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.

person Gregory Demin    schedule 29.05.2020
comment
Большое спасибо за это. Маленькая точка, однако var_lab (rdt [[each_name]]) = qlabels [[each_name]] не работает var_lab (rdt [[each_name]]) ‹- qlabels [[each_name]] (согласно руководству) работает. если вы хотите отредактировать. Ваше здоровье. - person Peter King; 08.06.2020
comment
@PeterKing Спасибо за сообщение. Я отредактировал ответ. Но на самом деле это очень странно - в этом контексте не должно быть никакой разницы. - person Gregory Demin; 08.06.2020

У меня нет 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.)

person r2evans    schedule 27.05.2020
comment
Это может быть очень сложно, но, боюсь, я этого просто не понимаю. Я не понимаю, для чего предназначена ваша функция my_fake_labels. Это прокси для expss apply_labels ради аргумента? Что такое список (...)? Пожалуйста, простите борющегося новичка. - person Peter King; 28.05.2020
comment
Я напишу фальшивую функцию (так как у меня нет опыта). Добавьте к этому эта фальшивая функция принимает те же аргументы, что и ваш apply_labels, поэтому ведет себя так же, насколько нам это нужно здесь. Просто замените его своим expss::apply_labels и посмотрите, что произойдет. - person r2evans; 28.05.2020
comment
list(...) - это способ R (пере) упаковки аргументов произвольной (0 или более) длины. - person r2evans; 28.05.2020
comment
Пытался do.call добавить первый параметр (имя таблицы данных) tdt ‹- copy (rdt) comslist‹ - prepend (comslist, tdt) # используя purrr tdt ‹- do.call (expss :: apply_labels, comslist) результат был Ошибка в UseMethod (apply_labels): нет применимого метода для 'apply_labels', применяемого к объекту символа класса - person Peter King; 30.05.2020
comment
Я думаю, что purrr::prepend удаляет класс из вашего comslist, поэтому expss::apply_labels не знает, что с ним делать. Я не знаю, почему вы добавляете в список буквальную строку "tdt", но это кажется странным. Разве ты не можешь просто сделать do.call(apply_labels, c(tdt, comslist))? - person r2evans; 30.05.2020