如何在R中创建、构建、维护和更新数据码本?

如何在R中创建、构建、维护和更新数据码本?,r,metadata,data-management,R,Metadata,Data Management,为了便于复制,我喜欢为每个数据帧保存一个带有元数据的代码本。数据码本是: 一份书面的或计算机化的清单,对数据库中包含的变量进行清晰、全面的描述。Marczyk等人() 我想记录变量的以下属性: 名字 说明(标签、格式、比例等) 资料来源(如世界银行) 源媒体(url和访问日期、CD和ISBN或其他) 磁盘上源数据的文件名(有助于合并代码本) 注释 例如,这就是我正在实现的用8个变量记录数据框mydata1中的变量: code.book.mydata1 <- data.frame(var

为了便于复制,我喜欢为每个数据帧保存一个带有元数据的代码本。数据码本是:

一份书面的或计算机化的清单,对数据库中包含的变量进行清晰、全面的描述。Marczyk等人()

我想记录变量的以下属性:

  • 名字
  • 说明(标签、格式、比例等)
  • 资料来源(如世界银行)
  • 源媒体(url和访问日期、CD和ISBN或其他)
  • 磁盘上源数据的文件名(有助于合并代码本)
  • 注释
例如,这就是我正在实现的用8个变量记录数据框mydata1中的变量:

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

code.book.mydata1您可以使用
attr
函数向任何R对象添加任何特殊属性。例如:

x <- cars
attr(x,"source") <- "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"))
这将列出所有非标准属性(标准为:名称、行名称、数据框中的类)

在此基础上,您可以编写一个简短的函数来列出所有非标准属性和值。下面的方法确实有效,但不是很简洁……您可以对其进行改进并组成一个函数:)

首先,定义uniqe(=非标准)属性:

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

有关变量标签的问题,请检查package foreign的
read.spss
函数,因为它正是您所需要的:将值标签保存在attrs部分。其主要思想是attr可以是数据帧或其他对象,因此您不需要为每个变量创建唯一的“attr”,只需创建一个(例如,命名为“varable labels”)并将所有信息保存在其中。您可以像这样调用:
attr(x,“variable.labels”)['foo']
其中'foo'代表所需的变量名。但要了解更多详细信息,请检查上面引用的函数以及导入的数据帧的属性


我希望这些可以帮助您以比我上面尝试的更简洁的方式编写所需的函数:)

更高级的版本是使用S4类。例如,在生物导体中,用于存储微阵列数据及其相关实验元数据

中所述的MIME对象看起来与您要查找的对象非常相似:

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"))
experimentData这里的
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"
合并示例:

> dat2 <- data.frame(D = 1:5)
> comment(dat2$D) <- "Label 4"
> dat3 <- cbind(dat, dat2)
> comment(dat3$D)
[1] "Label 4"
因此,这些类型的操作需要显式处理。要真正做到您想要的,您可能需要编写特殊版本的函数,这些函数在提取/合并操作期间维护注释/元数据。或者,您可能希望研究如何生成自己的对象类,例如,作为一个包含数据帧的列表和保存元数据的其他组件。然后为保存元数据的函数编写方法


这方面的一个例子是zoo包,它为一个时间序列生成一个列表对象,其中包含额外的组件,这些组件包含排序和时间/日期信息等,但从子集等的角度来看,它仍然像一个普通对象一样工作,因为作者提供了函数的方法,如
[
等。

我是如何做到这一点的,有点不同,也没有太多的技术性。我通常遵循的指导原则是,如果文本不是设计为对计算机有意义,而只是对人类有意义,那么它就属于源代码中的注释

这可能让人觉得“技术含量低”,但有一些很好的理由:

  • 当其他人将来拿起您的代码时,很直观的一点是,注释是明确地供他们阅读的。在数据结构中不寻常的地方设置的参数对于未来的用户可能并不明显
  • 跟踪抽象对象内部设置的参数需要相当多的规程。创建代码注释也需要规程,但注释的缺失是显而易见的。如果描述是作为对象的一部分进行的,那么浏览代码并不能使这一点变得明显。然后代码会变得更少“识字”在“识字编程”一词的意义上
  • 在数据对象中携带数据描述很容易导致描述不正确。例如,如果将包含测量单位(kg)的列乘以2.2以将单位转换为磅,则可能会发生这种情况。很容易忽略更新元数据的需要

显然,将元数据与对象一起携带有一些真正的优势。如果您的工作流程使上述各点不那么密切,那么在您的数据结构中创建元数据附件可能会很有意义。我的目的只是想与大家分享一些“低技术”的原因“可能会考虑采用基于评论的方法。

从2020年起,有R包直接专用于代码本,可能适合您的需要

  • 码本包是一个综合包,可以生成不同格式的码本(具有公共属性和描述性统计)。它有一个和一篇论文(Arslan,2019)。该论文在图1中还对不同方法进行了比较。
    这是一个例子

  • dataspice包(由rOpenSci提供特色)专门用于生成可以
    attribs <- as.data.frame(attribs)
    names(attribs) <- c('name', 'value')
    
    write.csv(attribs, 'foo.csv')
    
    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"))
    
    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"
    
    > comment(dat3)
    NULL