Как создавать, структурировать, поддерживать и обновлять кодовые книги данных в R? - PullRequest
23 голосов
/ 17 марта 2011

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

письменный или компьютеризированный список, содержащий четкое и полное описание переменных, которые будут включены в базу данных. Марчик и др. ( 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))
)

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

Ответы [ 4 ]

7 голосов
/ 17 марта 2011

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

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"))

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

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

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

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» для каждой переменной, а делать только один (например, с именем «varable label») и сохранять всю информацию там. , Вы можете вызвать как: attr(x, "variable.labels")['foo'], где 'foo' обозначает требуемое имя переменной. Но проверьте функцию, упомянутую выше, а также атрибуты импортированных фреймов данных для более подробной информации.

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

5 голосов
/ 17 марта 2011

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

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

experimentData <- new("MIAME", name = "Pierre Fermat",
          lab = "Francis Galton Lab", contact = "pfermat@lab.not.exist",
          title = "Smoking-Cancer Experiment", abstract = "An example ExpressionSet",
          url = "www.lab.not.exist", other = list(notes = "Created from text files"))
4 голосов
/ 17 марта 2011

Здесь может быть полезна функция 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, который генерирует объект списка для временного ряда с дополнительными компонентами, содержащими информацию о порядке и времени / дате и т. Д., но все еще работает как обычный объект с точки зрения поднабора и т. д., поскольку авторы предоставили методы для таких функций, как [ и т. д.

3 голосов
/ 17 марта 2011

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

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

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

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

...