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.
- 一些软件包包含许多数据集。
构建您自己的数据帧
[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$var1
和 mydat2$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"。
有时我们需要在数据集中复制一些行。例如,如果我们想要生成一个具有 面板数据 结构的假数据集。在这种情况下,我们首先会生成时间不变变量,然后将每行按给定的标量复制以创建随时间变化的变量。
可以使用 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]
- ↑ AER 包 https://cran.r-project.org.cn/web/packages/AER/index.html
- ↑ EcDat 包 https://cran.r-project.org.cn/web/packages/Ecdat/index.html
- ↑ “对英格兰贫困变化原因的调查,主要是在最后两个人口普查期间(第一部分)” - GU Yule - 《皇家统计学会杂志》,1899 年 6 月,第 283 页
- ↑ 使用 reshape 包重塑数据 : http://www.jstatsoft.org/v21/i12
- ↑ tables 包的示意:https://cran.r-project.org.cn/web/packages/tables/vignettes/tables.pdf
- ↑ 合并数据帧,同时保留行
- ↑ R 数据手册 https://cran.r-project.org.cn/doc/manuals/R-data.html
- ↑ Paul Murrell 的 数据技术入门 http://www.stat.auckland.ac.nz/~paul/ItDT/