学习R语言:数据框

目录

本文内容来自《R 语言编程艺术》(The Art of R Programming),有部分修改

数据框 (data.frame) 类似矩阵,有行和列,但数据框中的每一列可以使不同的模式 (mode)。

创建数据框

kids <- c("Jack", "Jill")
ages <- c(12, 10)
d <- data.frame(
    kids, ages,
    stringsAsFactors=FALSE
)
print(d)
  kids ages
1 Jack   12
2 Jill   10

stringsAsFactors 参数用于将字符串转换为因子 (factor),默认值为 TRUE。

访问数据框

数据框是一个列表,可以通过索引或者组件名访问

print(d[[1]])
[1] "Jack" "Jill"
print(d$kids)
[1] "Jack" "Jill"

可以使用类似矩阵的方式

print(d[, 1])
[1] "Jack" "Jill"

str() 函数查看数据框

str(d)
'data.frame':	2 obs. of  2 variables:
 $ kids: chr  "Jack" "Jill"
 $ ages: num  12 10

扩展案例:考试成绩的回归分析(续)

score <- read.csv("../data/student-mat.csv", header=T)
head(score)

其他矩阵式操作

矩阵操作可以应用到数据框中

提取子数据框

score[2:5,]
print(score[2:5, 32])
[1]  5  8 14 10
print(class(score[2:5, 32]))
[1] "integer"
print(score[2:5, 32, drop=FALSE])
  G2
2  5
3  8
4 14
5 10
print(class(score[2:5, 32, drop=FALSE]))
[1] "data.frame"

筛选

score[score$G1 > 17,]

处理缺失值

R 会尽量处理缺失数据,但有些时候需要指定 na.rm=TRUE 告诉函数忽略缺失值

x <- c(2, NA, 4)
print(mean(x))
[1] NA
print(mean(x, na.rm=TRUE))
[1] 3

subset() 函数会自动忽略缺失值

subset(score, G1>17)

complete.cases() 去掉含有缺失值的观测

kids <- c("Jack", NA, "Jillian", "John")
states <- c("CA", "MA", "MA", NA)
d4 <- data.frame(
    kids,
    states,
    stringsAsFactors=FALSE
)
print(d4)
     kids states
1    Jack     CA
2    <NA>     MA
3 Jillian     MA
4    John   <NA>
print(complete.cases(d4))
[1]  TRUE FALSE  TRUE FALSE
d5 <- d4[complete.cases(d4),]
print(d5)
     kids states
1    Jack     CA
3 Jillian     MA

使用 rbind()cbind() 等函数

两个数据框必须有相同的行数或列数

rbind() 添加新行时,添加的行通常是数据框或列表

print(d)
  kids ages
1 Jack   12
2 Jill   10
print(rbind(
    d, 
    list("Laura", 19)
))
   kids ages
1  Jack   12
2  Jill   10
3 Laura   19

使用原有列创建新列

eq <- cbind(
    score,
    score$G2 - score$G1
)
print(class(eq))
[1] "data.frame"
head(eq)

使用数据框的列表属性,增加新列

score$GDiff <- score$G2 - score$G1
head(score)

属性方式添加新列也支持循环补齐

print(d)
  kids ages
1 Jack   12
2 Jill   10
d$ones <- 1
print(d)
  kids ages ones
1 Jack   12    1
2 Jill   10    1

使用 apply()

如果数据框中的每一列数据类型相同,可以使用 apply() 函数

exam <- score[,31:33]
print(head(exam))
  G1 G2 G3
1  5  6  6
2  5  5  6
3  7  8 10
4 15 14 15
5  6 10 10
6 15 15 15
print(apply(exam, 1, max))
  [1]  6  6 10 15 10 15 12  6 
  ......

扩展案例:工资研究

all2006 <- read.csv(
    "../data/2006.csv.short",
    header=TRUE,
    as.is=TRUE
)
head(all2006)

做筛选

all2006 <- all2006[all2006$Wage_Per == "Year",]
all2006 <- all2006[all2006$Wage_Offered_From > 20000,]
all2006 <- all2006[all2006$Prevailing_Wage_Amount > 200,]

实际工资与普遍工资的比率

all2006$rat <- all2006$Wage_Offered_From / all2006$Prevailing_Wage_Amount
all2006

定义一个函数计算 rat 列的中位数

medrat <- function(dataframe) {
    return (median(dataframe$rat, na.rm=T))
}

print(medrat(all2006))
[1] 1.002423
se2006 <- all2006[grep("Software Engineer", all2006),]
prg2006 <- all2006[grep("Director", all2006),]
ee2006 <- all2006[grep("Industrial Engineer", all2006),]

使用下面的函数提取给定公司的子集

makecorp <- function(corpname) {
    t <- all2006[all2006$Employer_Name == corpname,]
    return (t)
}
corplist <- list(
    "THE OGILVY GROUP INC", "ogilvy",
    "ITT INDUSTRIES", "itt"
)

for (i in 1:(length(corplist)/2)) {
    corp <- corplist[2*i - 1]
    newdtf <- paste(corplist[2*i], "2006", sep="")
    assign(newdtf, makecorp(corp), pos=.GlobalEnv)
}
itt2006

合并数据框

使用 merge() 函数

d1 <- data.frame(
    kids=c("Jack", "Jill", "Jillian", "John"),
    states=c("CA", "MA", "MA", "HI"),
    stringsAsFactors=FALSE
)
print(d1)
     kids states
1    Jack     CA
2    Jill     MA
3 Jillian     MA
4    John     HI
d2 <- data.frame(
    ages=c(10, 7, 12),
    kids=c("Jill", "Lillian", "Jack"),
    stringsAsFactors=FALSE
)
print(d2)
  ages    kids
1   10    Jill
2    7 Lillian
3   12    Jack
d <- merge(d1, d2)
print(d)
  kids states ages
1 Jack     CA   12
2 Jill     MA   10

by.xby.y 两个参数可以指定合并的列名

d3 <- data.frame(
    ages=c(12, 10, 7),
    pals=c("Jack", "Jill", "Lillian")
)
print(merge(
    d1, d3,
    by.x="kids",
    by.y="pals"
))
  kids states ages
1 Jack     CA   12
2 Jill     MA   10

重复匹配可能会得出错误的结果

print(d1)
     kids states
1    Jack     CA
2    Jill     MA
3 Jillian     MA
4    John     HI
d2a <- rbind(
    d2,
    list(15, "Jill")
)
print(d2a)
  ages    kids
1   10    Jill
2    7 Lillian
3   12    Jack
4   15    Jill
print(merge(d1, d2a))
  kids states ages
1 Jack     CA   12
2 Jill     MA   10
3 Jill     MA   15

应用于数据框的函数

在数据框上应用 lapply()sapply() 函数

lapply() 中调用 f(),函数会作用域数据框中的每一列,将返回值置于一个列表中

print(d)
  kids states ages
1 Jack     CA   12
2 Jill     MA   10
dl <- lapply(d, sort)
print(dl)
$kids
[1] "Jack" "Jill"

$states
[1] "CA" "MA"

$ages
[1] 10 12

将列表强制转为数据框

注:排序后失去了记录的关联关系,这样做没有意义

print(as.data.frame(dl))
  kids states ages
1 Jack     CA   10
2 Jill     MA   12

扩展案例:应用 Logistic 模型

title <- c("Gender", "Length", "Diameter", "Height", "WholeWt", "ShuckedWt", "ViscWt", "ShellWt", "Rings")
aba <- read.csv(
    "../data/abalone.data",
    header=FALSE,
    col.names=title
)

将 Gender 列转换为 factor

aba$Gender <- as.factor(aba$Gender)

删掉幼鱼数据

abamf <- aba[aba$Gender != "I",]

逻辑回归模型训练函数,返回系数

lftn <- function(clmn) {
    glm(abamf$Gender ~ clmn, family=binomial)$coef
}

在每一列中应用该函数

loall <- sapply(abamf[,-1], lftn)
loall
print(class(loall))
[1] "matrix" "array" 

参考

学习 R 语言系列文章

快速入门

向量

矩阵和数组

列表

本文的 Jupyter Notebook 代码请访问如下项目:

https://github.com/perillaroc/the-art-of-r-programming