Как в R факторизовать и добавить значения меток в указанные столбцы c data.table, используя второй файл метаданных? - PullRequest
0 голосов
/ 19 июня 2020

Это часть проекта по переключению с SPSS на R. Хотя существуют хорошие инструменты для импорта файлов SPSS в R (expss), частью этого вопроса является попытка получить преимущества маркировки стиля SPSS, когда данные исходят из Исходники CSV. Это должно помочь преодолеть разрыв в обучении персонала между SPSS и R, предоставляя общий формат для data.tables независимо от формата файла.

Хотя CSV выполняет разумную работу по хранению данных, предоставление значимых данных безнадежно . Это неизбежно означает, что уровни и ярлыки переменных и факторов должны исходить откуда-то еще. В большинстве коротких примеров этого (например, в документации) практично просто жестко закодировать метаданные. Но для более крупных проектов имеет смысл хранить эти метаданные во втором CSV-файле.

Примеры данных файл

ID, varone, vartwo, varthree, varfour, varfive, varsix, varseven, vareight, varnine, varten 1,1,34,1`` 1`` 1,1,4, 2,1, 21,0,1`` 1,3,14,3,2 3,1,54,1`` 1,3,6,4,4 4,2,32,1,1,1`` 3, 7,4, 5,3,66,0 ,,, 1,3,9,3,3 6,2,43,1,, 1,, 1,12,2,1 7,2,26,0, ,, 1,2,11,1, 8,3`` 1,1`` 2,15,1,4 9,1,34,1`` 1`` 1,12,3,4 10,2 , 46,0 ,,,, 3,13,2, 11,3,39,1,1,1,, 3,7,1,2 12,1,28,0 ,,, 1,1,6, 5,1 13,2,64,0`` 1`` 2,11`` 3 14,3,34,1,1`` 3,10,1,1 15,1,52,1`` 1 , 1,1,8,6,

Пример файла метаданных

Rowlabels, ID, varone, vartwo, varthree, varfour, varfive, varsix, varseven, vareight, varnine, varten varlabel ,, Вопрос один, вопрос два, вопрос три, вопрос четыре, вопрос пять, вопрос шесть, вопрос седьмой, вопрос восемь, вопрос девять, вопрос десять varrole, Уникальный, Отношение, Уникальный, Фильтр, Фильтр, Фильтр, Фильтр, Отношение, Фильтр, Отношение, Отношение отсутствует, Ошибка, Ошибка, Игнорируется, Ошибка, Не отмечено, Не отмечено, Не отмечено, Ошибка, Ошибка, Ошибка, Игнорируемый vallable, Один, Нет, Проверено, Проверено, Проверено, x, Один, A, Поддержка vallable ,, Два ,, Да ,,,, y, Два, B, Нейтральное значение ,, Три ,,,,,, z, Три, C, Противоположное значение ,,,,,,,,, Четыре, D, Не знаю vallable ,,,,,,,,, Five, E, vallable ,,,,,,,,, Six, F, vallable ,,,,,,,,, Seven, G, vallable ,,,,, ,,,, Восемь ,, vallable ,,,,,,,,, Девять ,, vallable ,,,,,,,,, Ten ,, vallable ,,,,,,,, Одиннадцать ,, vallable ,,, ,,,,,, Двенадцать ,, vallable ,,,,,,,,, Тринадцать ,, vallable ,,,,,,,,, Четырнадцать ,, vallable ,,,,,,,, Пятнадцать ,,

Итак, общие элементы - это имена столбцов, которые являются ключом к обоим файлам.

Первый столбец файла метаданных описывает роль строки для файла данных, поэтому varlabel предоставляет метку переменной для каждого столбец varrole описывает аналити c цель отсутствующей переменной описывает, как обрабатывать отсутствующие данные varlabel описывает метку для уровня фактора, начиная от одного до такого количества lab els как есть.

Верно! Вот код, который работает:

```#Libraries
library(expss)
library(data.table)
library(magrittr)```
readcsvdata <- function(dfile)
{
# TESTED - Working
print("OK Lets read some comma separated values")
rdata <- fread(file = dfile, sep = "," , quote = "\"" , header = TRUE, stringsAsFactors = FALSE, 
na.strings = getOption("datatable.na.strings",""))
return(rdata)
}
rawdatafilename <- "testdata.csv"
rawmetadata <- "metadata.csv"

mdt <- readcsvdata(rawmetadata)
rdt <- readcsvdata(rawdatafilename)
names(rdt)[names(rdt) == "ï..ID"] <- "ID" # correct minor data error
commonnames <- intersect(names(mdt),names(rdt))  # find common variable names so metadata applies 
commonnames <- commonnames[-(1)] # remove ID
qlabels <- as.list(mdt[1, commonnames, with = FALSE])

(Здесь я копирую данные rdt просто для того, чтобы я мог вернуться к исходным данным без повторного запуска предыдущих фрагментов чтения и очистки всякий раз, когда я вносить изменения, которые не работают.

# set var names to columns
for (each_name in commonnames) # loop through commonnames and qlabels
{  
    expss::var_lab(tdt[[each_name]]) <- qlabels[[each_name]]
}

Хорошо, вот здесь я падаю. Отсюда неудача

factorcols <- as.vector(commonnames)  # create a vector of column names (for later use)
for (col in factorcols) 
  { 
  print( is.na(mdt[4, ..col])) # print first row of value labels (as test)
  if (is.na(mdt[4, ..col])) factorcols <- factorcols[factorcols != col] 
# if not a factor column, remove it from the factorcol list and dont try to factor it
  else {  # if it is a vector factorise
    print(paste("working on",col))  # I have had a lot of problem with unrecognised ..col variables
    tlabels <- as.vector(na.omit(mdt[4:18, ..col]))  # get list of labels from the data column}
    validrange <- seq(1,lengths(tlabels),1)            # range of valid values is 1 to the length of labels list
    print(as.character(tlabels)) # for testing
    print(validrange) # for testing
    tdt[[col]] <- factor(tdt[[col]], levels = validrange, ordered = is.ordered(validrange), labels = as.character(tlabels))
    # expss::val_lab(tdt[, ..col]) <- tlabels
    tlabels = c()  # flush loop variable
    validrange = c() # flush loop variable
  }
}

Итак, проблема обнаруживается здесь, когда мы проверяем таблицу данных .

tdt

метки были применены как целые векторы к каждой записи столбца, за исключением случаев, когда в векторе есть только одно значение ("проверено" для varfour и varfive) tdt идентификатор (число) 1 varone (fctr) c («Один», «Два», «Три») 1 (должно быть «Один» 1) vartwo (S3: маркированный) 34 varthree (fctr) c («Нет», «Да») 1 (должно быть «Нет» 1) varfour (fctr) NA varfive (fctr) Проверено И загадка этот код отлично работает с отдельными столбцами, когда я не использую для l oop переменную

# test using column name
tlabels <- c("one","two","three")
validrange <- c(1,2,3)
factor(tdt[,varone], levels = validrange, ordered=is.ordered(validrange), labels = tlabels)

1 Ответ

1 голос
/ 21 июня 2020

Кажется, проблема в строке tlabels <- as.vector(na.omit(mdt[4:18, ..col])). Он не делает вектор, как вы ожидаете. В отличие от обычного data.frame data.table не удаляет измерения, когда вы указываете один столбец в индексе. И as.vector ничего не делает с data.frames / data.tables. Таким образом, tlabels остается data.table. Эту строку нужно переписать как tlabels <- na.omit(mdt[[col]][4:18]). Пример:

library(data.table)
mdt = as.data.table(mtcars)
col = "am"
tlabels <- as.vector(na.omit(mdt[3:6, ..col])) # ! tlabels is data.table 
str(tlabels)
# Classes ‘data.table’ and 'data.frame':    4 obs. of  1 variable:
#     $ am: num  1 0 0 0
# - attr(*, ".internal.selfref")=<externalptr> 

as.character(tlabels) # character vector of length 1
# [1] "c(1, 0, 0, 0)"

tlabels <- na.omit(mdt[[col]][3:6]) # vector 
str(tlabels)
# num [1:4] 1 0 0 0
as.character(tlabels) # character vector of length 4
# [1] "1" "0" "0" "0"
...