跳转到内容

R 编程/数据框操作

来自维基教科书,开放世界中的开放书籍

在本节中,我们将介绍用于读取、管理和清理数据框的方法。

在 R 中,数据框是一个由相同长度的向量组成的列表。它们不需要是相同类型。例如,您可以在一个数据框中组合一个逻辑向量、一个字符向量和一个数值向量。

读取和保存数据

[编辑 | 编辑源代码]

如果数据已处于 R 格式 (.Rda.Rdata),您可以使用 load() 将其加载到内存中。您可以使用 save() 将数据保存到 R 格式。

load("mydata.Rda")
save(list='mydata',file="mydata.Rda")

示例数据集

[编辑 | 编辑源代码]
  • 大多数软件包都包含示例数据集来测试函数。
  • data() 函数不带参数时会给出所有已加载软件包中所有示例数据集的列表。
  • 如果您想将它们加载到内存中,您只需要使用 data 函数并将数据集的名称作为参数。
  • str_data() (sfsmisc) 给出软件包中所有数据集的结构。
> data() # lists all the datasets in all the packages in memory
> data(package="datasets") # lists all the datasets in the "datasets" package
> data(Orange) # loads the orange dataset in memory
> ?Orange # Help for the "Orange" Datasets
> str_data("datasets") # gives the structure of all the datasets in the datasets package.
  • 一些软件包包含许多数据集。
    • datasets 软件包
    • AER 软件包 [1] 包含计量经济学中一些重要教科书的复制数据集。
    • EcDat 软件包 [2] 包含《应用计量经济学杂志》、《商业与经济统计杂志》等期刊的复制档案。

构建您自己的数据帧

[edit | edit source]

您可以使用向量创建一个数据帧。

N <- 100
u <- rnorm(N)
x1 <- rnorm(N)
x2 <- rnorm(N)
y <- 1 + x1 + x2 + u
mydat <- data.frame(y,x1,x2)

R 拥有一个类似电子表格的数据编辑器。您可以使用它将数据输入电子表格。

mydat <- edit(data.frame())

从剪贴板读取表格

> mydat <- read.table("clipboard")

您还可以使用 gsource() (Zelig) 在代码中读取空格分隔的表格。以下是以 Yule 1899 数据为例。 [3]

mydat <- gsource(var.names = "id union pauperism out old  pop", 
variables = "
1 Kensington 27 5 104 136
2 Paddington  47 12 115 111
3 Fulham 31 21 85 174
")

您可以更改数据帧的列名。

c1 <- c('A','B','C')
c2 <- c('Alpha','Bravo','Charlie')
c3 <- c('1','2','3')
mydf <- data.frame(c1,c2,c3)
colnames(mydf) <- c('ColName1','ColName2','ColName3')

描述数据帧

[edit | edit source]

有各种方法可以检查数据帧,例如

  • str(df) 给出数据非常简短的描述
  • names(df) 给出每个变量的名称
  • summary(df) 给出每个变量的一些非常基本 的汇总统计量
  • head(df) 显示前几行
  • tail(df) 显示最后几行。

浏览数据

[edit | edit source]
  • 您可以使用 View() 在电子表格中浏览数据。根据您的操作系统,此选项并非总是可用,结果也并非总是相同。
  • 您可以使用 head() 打印前几行,使用 tail() 打印最后几行。
View(mydata)
head(mydata, n = 20) # n = 20 means  that the first 20 lines are printed in the R console
  • RStudio 拥有一个不错的 数据浏览器 (View(mydata))。
  • RKward 也拥有一个不错的 数据浏览器
  • Paul Murrell 目前正在开发 rdataviewer 软件包 (pdf).

绑定行或列

[edit | edit source]

在使用数据帧时,您通常会更改数据,并且可以对数据帧进行的一些更改之一是添加列或行,从而增加数据帧的维度。有几种不同的方法可以做到这一点,但最简单的方法是 cbind()rbind(),它们是 base 软件包的一部分

mydata <- cbind(mydata, newVector)
mydata <- rbind(mydata, newVector)

请记住,newVector 的长度应与您要附加它的数据帧边的长度匹配。例如,在 cbind() 命令中,以下语句应为 TRUE

dim(mydata)[1]==length(newVector)

要查看更多示例,您始终可以执行 ?base::cbind?base::rbind

附加数据

[edit | edit source]

R 相对于 Stata 的一大优势是您可以同时处理多个数据集。您只需要指定数据集的名称,并在每个变量名称之前加上“$”符号 (例如 mydat1$var1mydat2$var1)。如果您只使用一个数据集,并且不想为每个变量重复写数据集名称作为前缀,您可以使用 attach()

mydata$var1
attach(mydata)
var1
detach(mydata)

检测重复项

[edit | edit source]

当您想要清理数据集时,检查数据中是否存在相同的信息通常很有用。R 提供了一些函数来检测重复项。

  • duplicated() 查看重复元素并返回一个逻辑向量。您可以使用 table() 来汇总此向量。
  • Duplicated() (sfsmisc) 对此命令进行了概括。Duplicated() 只用 “NA” 标记唯一值。
  • remove.dup.rows() (cwhmisc).
  • unique() 只保留数据集中唯一的行。
  • distinct() (dplyr) 只保留数据集中唯一的/不同的行。


library("Zelig")
mydat <- gsource(
variables = "
1 1 1 1
1 1 1 1
1 2 3 4
1 2 3 4
1 2 2 2
1 2 3 2")
unique(mydat) # keep unique rows
library(cwhmisc)
remove.dup.rows(mydat) # similar to unique()
table(duplicated(mydat)) # table duplicated lines
mydat$dups <- duplicated(mydat) # add a logical variable for duplicates

创建和删除变量

[edit | edit source]

要创建一个新变量

mydata$newvar <- oldvar

如果您想要删除数据集中某个变量,可以将 NULL 分配给该变量

# Delete the x variable in the df data frame.
df$x <- NULL

重命名变量

[edit | edit source]
  • 可以通过重新定义数据帧的名称向量来重命名变量。
  • reshape 软件包中还有一个 rename() 函数。
df <- data.frame(x = 1:10, y = 21:30)
names(df)
names(df) <- c("toto","tata")
names(df)
names(df)[2] <- "titi"
names(df)

创建数据的子集

[edit | edit source]

可以使用 subset() 对数据进行子集化。第一个参数是数据集的名称,第二个参数是一个逻辑条件,用于说明哪些行将包含在新数据集中,最后一个参数是将包含在新数据集中 的变量列表。

在以下示例中,我们生成了一个假数据集,并使用 subset() 命令选择感兴趣的行和列。我们选择 x1 > 0 且 x2 < 0 的行,并且只保留 x1 和 x2 作为变量。

N <- 100
x1 <- rnorm(N)
x2 <- 1 + rnorm(N) + x1
x3 <- rnorm(N) + x2
mydat <- data.frame(x1,x2,x3)
subset(x = mydat, subset = x1 > 0 & x2 < 0, select = c(x1,x2))
subset(x = mydat, subset = x1 > 0 & x2 < 0, select = - x3) # the same.

也可以使用 select 选项重新排序列。

subset(x = mydat, subset = x1 > 0 & x2 < 0, select = c(x1,x2))
subset(x = mydat, subset = x1 > 0 & x2 < 0, select = c(x2,x1))

排序和排列

[edit | edit source]
  • order()
mydat[order(var1,var2),]

假设您想随机化数据集中 的顺序。您只需要从均匀分布中生成一个向量,并按照该向量进行排序。

df[order(runif(nrow(df))),]

检测缺失值

[edit | edit source]
  • is.na() 返回一个逻辑向量,如果数据集中 的任何变量都缺失,则等于 TRUE,否则等于 FALSE。
  • complete.cases() 返回一个逻辑向量,如果所有案例都完整,则表示 TRUE,否则表示 FALSE。
> table(complete.cases(df))

重塑数据帧

[edit | edit source]

如果您处理面板数据,这个主题很重要。 面板数据 可以以宽格式存储,每个单元一个观测值,每个时间段一个变量,也可以以长格式存储,每个单元和时间段一个观测值。reshape() 将数据集重塑为宽格式或长格式。

> country <- c("'Angola'","'UK'","'France'")
> gdp.1960 <- c(1,2,3)
> gdp.1970 <- c(2,4,6)
> mydat <- data.frame(country,gdp.1960,gdp.1970)
> mydat # wide format
  country gdp.1960 gdp.1970
1  Angola       1       2
2      UK       2       4
3  France       3       6
> reshape( data = mydat, varying = list(2:3) , v.names = "gdp", direction = "long") # long format
    country time gdp id
1.1  Angola    1   1  1
2.1      UK    1   2  2
3.1  France    1   3  3
1.2  Angola    2   2  1
2.2      UK    2   4  2
3.2  France    2   6  3
  • varying 给出随时间变化的列的编号
  • v.names 给出随时间变化的变量的前缀
  • direction 给出方向,要么是 "long",要么是 "wide"。
  • 另请参阅 
    • reShape() (Hmisc)
    • 参见 Hadley Wickham 的 reshape[4]
    • 参见 Duncan Murdoch 的 tables[5]
[编辑 | 编辑源代码]

扩展数据集

[编辑 | 编辑源代码]

有时我们需要在数据集中复制一些行。例如,如果我们想要生成一个具有 面板数据 结构的假数据集。在这种情况下,我们首先会生成时间不变变量,然后将每行按给定的标量复制以创建随时间变化的变量。

可以使用 epicalc 包中的 expand() 函数(由于该包不再存在,因此在 [1] 中给出了扩展选项)。这将把每行乘以给定的数字。

N <- 1000
T <- 5
wide <- data.frame(id = 1:N,f = rnorm(N),  rep = T)
library("epicalc")
long <- expand(wide,index.var = "rep")
long$time <- rep(1:T,N)

我们也可以使用“自己动手解决方案”或创建自己的函数。想法很简单。我们创建一个向量,该向量为每行给出应复制的次数(在下面的示例中为 dups)。然后,我们使用 rep() 函数创建一个向量,该向量根据我们的需要重复行号。最后一步创建一个新数据集,该数据集根据所需模式重复行。

expand <- function(df,dups){
	df$dups <- dups
	pattern <- rep(1:nrow(df), times=df$dups)
	df2 <- df[pattern,]
	index <- function(x){
		1:length(x)
		}
	df2$year <- unlist(tapply(df2$dups, df2$id, index))
	df2$dups <- NULL 
	return(df2)
	}

df <- data.frame(x = rnorm(3), id = 1:3)
dups = c(3,1,2)
expand(df,dups)

合并数据帧

[编辑 | 编辑源代码]

合并数据可能会非常混乱,尤其是在多次合并的情况下。这是一个简单的例子 

我们有一个描述作者的表格 

> authors <- data.frame(
+     surname = I(c("Tukey", "Venables", "Tierney", "Ripley", "McNeil")),
+     nationality = c("US", "Australia", "US", "UK", "Australia"),
+     deceased = c("yes", rep("no", 4)))
> authors
   surname nationality deceased
1    Tukey          US      yes
2 Venables   Australia       no
3  Tierney          US       no
4   Ripley          UK       no
5   McNeil   Australia       no

还有一个描述书籍的表格

> books <- data.frame(
+     name = I(c("Tukey", "Venables", "Tierney",
+              "Ripley", "Ripley", "McNeil", "R Core")),
+     title = c("Exploratory Data Analysis",
+               "Modern Applied Statistics ...",
+               "LISP-STAT",
+               "Spatial Statistics", "Stochastic Simulation",
+               "Interactive Data Analysis",
+               "An Introduction to R"),
+     other.author = c(NA, "Ripley", NA, NA, NA, NA,
+                      "Venables & Smith"))
> books
      name                         title     other.author
1    Tukey     Exploratory Data Analysis             <NA>
2 Venables Modern Applied Statistics ...           Ripley
3  Tierney                     LISP-STAT             <NA>
4   Ripley            Spatial Statistics             <NA>
5   Ripley         Stochastic Simulation             <NA>
6   McNeil     Interactive Data Analysis             <NA>
7   R Core          An Introduction to R Venables & Smith

我们想根据作者姓名(第一个数据集中为“surname”,第二个数据集中为“name”)将书籍和作者表格合并。我们使用 merge() 命令。我们指定第一个和第二个数据集的名称,然后使用 by.x 和 by.y 指定两个数据集中的标识符。all.x 和 all.y 指定我们是否要保留第一个和第二个数据集的所有观测值。在这种情况下,我们希望拥有书籍数据集的所有观测值,但只保留与书籍数据集中观测值匹配的作者数据集的观测值。

> final <- merge(books, authors, by.x = "name", by.y = "surname", sort=F,all.x=T,all.y=F)
> final
      name                         title     other.author nationality deceased
1    Tukey     Exploratory Data Analysis             <NA>          US      yes
2 Venables Modern Applied Statistics ...           Ripley   Australia       no
3  Tierney                     LISP-STAT             <NA>          US       no
4   Ripley            Spatial Statistics             <NA>          UK       no
5   Ripley         Stochastic Simulation             <NA>          UK       no
6   McNeil     Interactive Data Analysis             <NA>   Australia       no
7   R Core          An Introduction to R Venables & Smith        <NA>     <NA>

也可以合并两个 data.frame 对象,同时保留其中一个合并对象的行的顺序。[6]

参考资料

[编辑 | 编辑源代码]
  1. AER 包 https://cran.r-project.org.cn/web/packages/AER/index.html
  2. EcDat 包 https://cran.r-project.org.cn/web/packages/Ecdat/index.html
  3. “对英格兰贫困变化原因的调查,主要是在最后两个人口普查期间(第一部分)” - GU Yule - 《皇家统计学会杂志》,1899 年 6 月,第 283 页
  4. 使用 reshape 包重塑数据 : http://www.jstatsoft.org/v21/i12
  5. tables 包的示意:https://cran.r-project.org.cn/web/packages/tables/vignettes/tables.pdf
  6. 合并数据帧,同时保留行
  7. R 数据手册 https://cran.r-project.org.cn/doc/manuals/R-data.html
  8. Paul Murrell 的 数据技术入门 http://www.stat.auckland.ac.nz/~paul/ItDT/


前一个:随机数生成 索引 下一个:导入和导出数据
华夏公益教科书