Подтвердить что ты не робот

Как создавать, структурировать, поддерживать и обновлять кодовые книги данных в R?

В интересах репликации мне нравится хранить кодовую книгу с метаданными для каждого фрейма данных. Кодовая книга данных:

письменный или компьютеризированный список, который обеспечивает четкое и полное описание переменных, которые будут включены в базу данных. Marczyk et al (2010)

Мне нравится документировать следующие атрибуты переменной:

  • имя
  • описание (метка, формат, масштаб и т.д.)
  • источник (например, Всемирный банк)
  • исходный носитель (URL-адрес и дата доступа, CD и ISBN или что-то еще)
  • имя файла исходных данных на диске (помогает при слиянии кодовых книг)
  • заметки

Например, это то, что я реализую для документирования переменных в массиве данных mydata1 с 8 переменными:

code.book.mydata1 <- data.frame(variable.name=c(names(mydata1)),
     label=c("Label 1",
              "State name",
              "Personal identifier",
              "Income per capita, thousand of US$, constant year 2000 prices",
              "Unique id",
              "Calendar year",
              "blah",
              "bah"),
      source=rep("unknown",length(mydata1)),
      source_media=rep("unknown",length(mydata1)),
      filename = rep("unknown",length(mydata1)),
      notes = rep("unknown",length(mydata1))
)

Я пишу другую кодовую книгу для каждого набора данных, который я читал. Когда я объединять кадры данных, я также объединим соответствующие аспекты их связанной кодовой книги, чтобы документировать окончательную базу данных. Я делаю это, по существу копируя вставку кода выше и изменяя аргументы.

4b9b3361

Ответ 1

Вы можете добавить любой специальный атрибут к любому объекту R с помощью функции attr. Например:.

x <- cars
attr(x,"source") <- "Ezekiel, M. (1930) _Methods of Correlation Analysis_.  Wiley."

И увидим данный атрибут в структуре объекта:

> str(x)
'data.frame':   50 obs. of  2 variables:
 $ speed: num  4 4 7 7 8 9 10 10 10 11 ...
 $ dist : num  2 10 4 22 16 10 18 26 34 17 ...
 - attr(*, "source")= chr "Ezekiel, M. (1930) _Methods of Correlation Analysis_.  Wiley."

И также может загрузить указанный атрибут с помощью той же функции attr:

> attr(x, "source")
[1] "Ezekiel, M. (1930) _Methods of Correlation Analysis_.  Wiley."

Если вы добавляете только новые случаи в свой фрейм данных, данный атрибут не будет затронут (см.: str(rbind(x,x)), а при изменении структуры будут отображаться данные атрибуты (см. str(cbind(x,x))).


ОБНОВЛЕНИЕ: на основе комментариев

Если вы хотите перечислить все нестандартные атрибуты, проверьте следующее:

setdiff(names(attributes(x)),c("names","row.names","class"))

В этом списке перечислены все нестандартные атрибуты (стандартные: имена, строки .names, класс в кадрах данных).

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

Сначала определите атрибуты uniqe (= нестандартные):

uniqueattrs <- setdiff(names(attributes(x)),c("names","row.names","class"))

И создайте матрицу, которая будет содержать имена и значения:

attribs <- matrix(0,0,2)

Прокрутите нестандартные атрибуты и сохраните в матрице имена и значения:

for (i in 1:length(uniqueattrs)) {
    attribs <- rbind(attribs, c(uniqueattrs[i], attr(x,uniqueattrs[i])))
}

Преобразуйте матрицу в кадр данных и назовите столбцы:

attribs <- as.data.frame(attribs)
names(attribs) <- c('name', 'value')

И сохраните в любом формате, например.:

write.csv(attribs, 'foo.csv')

На ваш вопрос о метках переменных проверьте функцию read.spss из пакета foreign, так как он точно вам нужен: сохраняет метки значений в секции attrs. Основная идея заключается в том, что attr может быть кадром данных или другим объектом, поэтому вам не нужно создавать уникальную "attr" для каждой переменной, но сделать только одну (например, названную "метками переменной" ) и сохранять всю информацию там, Вы можете назвать: attr(x, "variable.labels")['foo'] где 'foo' означает имя требуемой переменной. Но для более подробной информации проверьте приведенную выше функцию, а также атрибуты импортированных фреймов данных.

Я надеюсь, что это может помочь вам написать требуемые функции гораздо более аккуратным способом, чем я пробовал выше!:)

Ответ 2

Более сложной версией будет использование классов S4. Например, в биокондукторе ExpressionSet используется для хранения данных микрочипов с соответствующими экспериментальными метаданными.

Объект MIAME, описанный в Раздел 4.4, выглядит очень похоже на то, что вы после:

experimentData <- new("MIAME", name = "Pierre Fermat",
          lab = "Francis Galton Lab", contact = "[email protected]",
          title = "Smoking-Cancer Experiment", abstract = "An example ExpressionSet",
          url = "www.lab.not.exist", other = list(notes = "Created from text files"))

Ответ 3

Здесь может быть полезной функция comment(). Он может устанавливать и запрашивать атрибут комментария для объекта, но имеет преимущество других обычных атрибутов, которые не печатаются.

dat <- data.frame(A = 1:5, B = 1:5, C = 1:5)
comment(dat$A) <- "Label 1"
comment(dat$B) <- "Label 2"
comment(dat$C) <- "Label 3"
comment(dat) <- "data source is, sampled on 1-Jan-2011"

который дает:

> dat
  A B C
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
5 5 5 5
> dat$A
[1] 1 2 3 4 5
> comment(dat$A)
[1] "Label 1"
> comment(dat)
[1] "data source is, sampled on 1-Jan-2011"

Пример слияния:

> dat2 <- data.frame(D = 1:5)
> comment(dat2$D) <- "Label 4"
> dat3 <- cbind(dat, dat2)
> comment(dat3$D)
[1] "Label 4"

но теряет комментарий на dat():

> comment(dat3)
NULL

чтобы эти виды операций нуждались в обработке явно. Чтобы действительно делать то, что вы хотите, вам, вероятно, потребуется написать специальные версии функций, которые вы используете, которые поддерживают комментарии/метаданные во время операций извлечения/слияния. В качестве альтернативы вам может понадобиться изучить собственные классы объектов - например, список с фреймом данных и другими компонентами, содержащими метаданные. Затем напишите методы для функций, которые вы хотите сохранить метаданные.

Пример в этих строках - это пакет zoo, который генерирует объект списка для временного ряда с дополнительными компонентами, содержащими информацию о заказе и времени/дате и т.д., но все же работает как обычный объект с точки зрения подмножества и т.д., потому что авторы предоставили методы для таких функций, как [ и т.д.

Ответ 4

Как я это делаю, это немного отличается и заметно менее технический. Я, как правило, придерживаюсь принципа, что если текст не предназначен для того, чтобы быть значимым для компьютера и имеет смысл только для людей, то он принадлежит комментариям в исходном коде.

Это может показаться скорее "низкотехнологичным", но для этого есть несколько веских причин:

  • Когда кто-то еще заберет ваш код в будущем, интуитивно понятно, что комментарии недвусмысленно предназначены для чтения. Параметры, установленные в необычных местах в структурах данных, могут быть не очевидны для будущего пользователя.
  • Отслеживание параметров, установленных внутри абстрактных объектов, требует справедливой дисциплины. Создание комментариев кода требует также дисциплины, но отсутствие комментария сразу становится очевидным. Если описания переносятся как часть объекта, взгляд на код не делает этого очевидным. Затем код становится менее "грамотным" в смысле "грамотного программирования" этого слова.
  • Несоблюдение описаний данных внутри объекта данных может привести к неправильным описаниям. Это может произойти, если, например, колонка, содержащая измерение в кг, умножается на 2,2 для преобразования единиц в килограммы. Было бы очень легко упустить необходимость обновления метаданных.

Очевидно, есть некоторые реальные преимущества для переноса метаданных вместе с объектами. И если ваш рабочий процесс делает вышеупомянутые точки менее родственными, тогда может возникнуть большой смысл создать вложение метаданных в вашу структуру данных. Мое намерение состояло только в том, чтобы поделиться некоторыми причинами, по которым можно было бы рассмотреть подход, основанный на "более низких технологиях".