R语言:50题搞定 data.table
简介
data.table 是 R 语言中用于处理表格数据的包,相当于 Python 语言的 pandas,是学习 R 语言数据分析与挖掘必备工具。接下来我们用 50 道题学习data.table 的各种技巧。
尽管 data.table 提供了与 data.frame 稍有不同的语法,但是非常简单好用,相对于 data.frame 速度极快,一旦你学会了 data.table,一般的就不太想回到 data.frame 了。
0.基础问题
1.新建 data.table
# 使用 data.table 直接创建
DT = data.table(
a = 1:6,
b = 7:12,
c = 13:18
)
DT
2.如何从 list 创建一个 dt
# 如何从以下的 list 创建一个 dt
list_1 <- c("a","b","c","d")
list_2 <- c("1","2","3","4")
list_3 <- c("aa","bb","cc","dd")
# 答案
DT <- data.table(V1= list_1, V2 =list_2, V3 = list_3 )
DT
3.如何从 data.frame 转换为 data.table
DF <- read.csv('test.csv')
print ( class(DF))
# 用 setDT 函数转换为 data.table
setDT(DF)
print (class(DF))
4.如何从data.table 转换为 data.frame
DT = data.table(
a = 1:6,
b = 7:12,
c = 13:18
)
print(class(DT))
# 用 setDF 函数转换为 data.frame
setDF(DT)
print(class(DT))
5.如何导入 csv 文件
# 用 fread : fast read 函数
DT <- fread('/home/kesci/input/rlang_dt2138/BostonHousing.csv')
head(DT)
6.如何只从csv 文件导入10行数据
# fread 函数的 nrows 参数指定读取行数
DT <- fread('/home/kesci/input/rlang_dt2138/BostonHousing.csv', nrows = 10)
DT
7.如何只从 csv 文件导入指定的数据列
# fread 函数的 select 参数指定读取的列名称
DT <- fread('/home/kesci/input/rlang_dt2138/BostonHousing.csv', select = c('crim', 'medv'))
head(DT)
8.如何获取 data.table 的基本信息:几行、几列、数据类型、汇总信息等等
DT <- fread('BostonHousing.csv')
# 几行、几列
print(nrow(DT))
print(ncol(DT))
# 数据类型
print(sapply(DT, class))
# 汇总信息
summary(DT)
9.如何重命名数据列
DT <- fread('BostonHousing.csv')
# setnames 方法重命名数据列
setnames(DT, old = "medv", new = "价格")
head(DT)
1.缺失值处理
10.如何判断 data.table 有缺失值
DT <- fread('BostonHousing.csv')
# 用 anyNA 判断
anyNA(DT)
11.如何查看哪些数据是缺失的
# Cars93 数据集中第16行数据有缺失值存在
DT <- fread('Cars93.csv' )
# Luggage.room 是 na
print(is.na(DT[16]))
12.如何获取缺失值所在的位置(行、列值)
DT <- fread('Cars93.csv')
output <- c() # 输出数组
# 遍历数据集
for(i in 1:nrow(DT)){
for(j in 1:ncol(DT)){
# 获取当前元素
curr_value <- DT[i, j,with=F][[1]]
if(is.na(curr_value)){
# 如果是缺失值,将其位置放入 output 中
position <- paste0('(', paste(i, j, sep=', '), ')')
output <- c(output, position)
}
}
}
output
13.如何统计每一列的缺失值
DT <- fread('Cars93.csv')
# summary 函数中有统计
# 因为已经知道Rear.seat.room , Luggage.room 这两列有缺失值,因此就只打印这两列的 summary 信息
summary(DT[, .(Rear.seat.room , Luggage.room)])
14.如何替换缺失值为 0
DT <- fread('Cars93.csv')
print(summary(DT[, .(Rear.seat.room , Luggage.room)]))
# 直接赋值
DT[ is.na(DT)] <- 0
print("对缺失值赋值后,可以看到这两列数据没有缺失值了")
print(summary(DT[, .(Rear.seat.room , Luggage.room)]))
15.如何替换缺失值为均值
DT <- fread('Cars93.csv')
replace_with_mean <- function(x){ifelse(is.na(x),mean(x, na.rm = TRUE),x)}
output <- DT[,lapply(.SD, replace_with_mean)]
summary(output)
2.选择数据与分组聚合计算
16.如何选择一列数据并返回 list
DT <- fread('BostonHousing.csv')
# 使用 [i,j, by] 语法
# i: 相当于 SQL 的 where
# j: 相当于 SQL 的 select
# by: 相当于 SQL 的 group by
class(DT[, medv])
## 方法二
# 如果不知道列名称的话,可以用索引数字来选择指定的列,例如 第一列数据
head(DT[, 1])
17.如何选择一列数据并返回 data.table
DT <- fread('BostonHousing.csv')
# 用 list(列名称),这样返回的是 data.table 类型
class(DT[, list(medv)])
# .() 是 list() 的简写
class(DT[, .(medv)])
18.如何选择多列数据
# 用 .() 选择多列数据
head(DT[, .(crim, medv) ])
## 方法二
# 用数字列表选择多个列
head(DT[, 1:3])
19.如何选择列的同时改变列名称
DT <- fread('BostonHousing.csv')
# 使用赋值语法
head(DT[, .("价格" = medv, "犯罪率"= crim) ])
20.如何删除指定的列
DT <- fread('BostonHousing.csv')
# 将需要删除的列名称放入一个数组中,前面加上 ! 就表示不需要指定的列
# 这里需要用字符串来指定列名
head( DT[, ! c("crim", "zn", "indus")])
21.如何按照指定的列排序
DT <- fread('BostonHousing.csv')
# 用 order 函数
head(DT[ order(medv)])
# 倒排
head(DT[ order(-medv)])
# 多个列排序
head(DT[ order(-medv, crim)])
# 排序,并选择指定的列
head(DT[ order(-medv, crim), .(medv, crim)])
22.如何筛选数据
DT <- fread('BostonHousing.csv')
# 类似于 SQL 的判断语法
head( DT[ medv == 50 & crim > 0.5 ])
# 加上排序
head( DT[ medv == 50 & crim > 0.5 ][order(crim)])
23.如何选择指定条件的数据并进行聚合计算(均值、最大值等)
DT <- fread('BostonHousing.csv')
# 筛选 medv 大于 30 的数据, 并计算 age 列的均值, tax 最大值
head( DT[medv > 30, .("Age 均值"= mean(age), "Tax 最大值"= max(tax) ) ])
24.如何分组计算唯一值 以汽车数据集为例,按 Manufacturer(汽车制造商) 分组,计算 Model 有多少个唯一值
DT <- fread('Cars93.csv')
# 用 unique 函数, 结合 list 来获取
DT[, .('Models'= .(list(unique(Model))), 'Length'= lengths( list(unique(Model))) ) ,Manufacturer ][order(Length,decreasing=T)]
25.如何进行分组聚合计算1 以汽车数据集为例, 先按 Manufacturer(汽车制造商) 分组,在统计每个制造商生产的数量
DT <- fread('Cars93.csv')
# 按照 Manufacturer 分组
# 用 .N 进行计数
head( DT[, .N , Manufacturer] )
26.如何进行分组聚合计算2 以汽车数据集为例, 先按 Manufacturer(汽车制造商), Type (类型) 分组,在计算价格的均值,最大值,最小值
head( DT[, .( mean(Price), max(Price), min(Price), .N) , .( Manufacturer, Type) ] )
27.如何进行分组聚合计算3 以汽车数据集为例, 先按 Manufacturer(汽车制造商), Type (类型) 分组,再计算价格的均值。对结果按照 Manufacturer(汽车制造商), Type (类型) 排序
# 对返回结果在使用 order 进行排序
head( DT[, .( mean(Price), max(Price), min(Price), .N) , .( Manufacturer, Type) ][order(Manufacturer, Type)] )
## 方法二
# 用 keyby 参数实现同样效果
head( DT[, .( mean(Price), max(Price), min(Price), .N) , keyby=.( Manufacturer, Type) ] )
28.如何选择所有数值类型的列
DT <- fread('Cars93.csv')
head(DT[, .SD, .SDcols = which(sapply(DT, is.numeric))])
29.如何按 Manufacturer(汽车制造商)分组计算所有数值类型的均值
DT <- fread('Cars93.csv')
# 获得所有数值类型的列: .SDcols = which(sapply(DT, is.numeric))
# 对数值列计算均值: lapply(.SD, mean)
# 按 Manufacturer 分组: by = Manufacturer
head(DT[, lapply(.SD, mean), .SDcols = which(sapply(DT, is.numeric)), by = Manufacturer])
3.综合性问题
30.如何获取每个 Manufacturer 的第一行数据
DT <- fread('Cars93.csv')
# 获取 一行数据: head(.SD, 1)
# 按 Manufacturer 分组并排序: keyby = Manufacturer
head( DT[, head(.SD, 1), keyby = Manufacturer])
31.如何设置数据列为主键列
DT <- fread('Cars93.csv')
# 设置 Type 为主键列
setkey(DT, Type)
32.如何获取 Type 为 Small 的所有数据
DT <- fread('Cars93.csv')
# 用 == 判断
head( DT [ Type == 'Small'] )
## 方法二
# 首先将 Type 设为主键
setkey(DT, Type)
# 用主键进行判断
head(DT['Small'])
33.如何获得 Type 为 'Midsize', 'Small' 的数据
DT <- fread('Cars93.csv')
# 首先将 Type 设为主键
setkey(DT, Type)
# 多个匹配
head(DT[c('Midsize', 'Small')], 2)
# 用 tail 看一下 Small 类型也被匹配了
tail(DT[c('Midsize', 'Small')], 2)
34.如何按 Manufacturer 分组后计算 Price 的方差
DT <- fread('Cars93.csv')
# 按 Manufacturer 分组
# 用 sd 方法计算 Price 的方差
head(DT[, sd(Price), Manufacturer])
35.如何获取 Type= Small, 按 Manufacturer 分组,计算 Price 的均值
DT <- fread('Cars93.csv')
# i: 判断语句
# j: 计算 Price 均值
# by: 按Manufacturer分组
DT[Type=='Small', mean(Price) , by= Manufacturer]
36.如何得到 Price 最大值所在的行
DT <- fread('Cars93.csv')
# 使用 tail 即可
tail(DT[order(Price)], 1)
37.如何得到Price 第5个最大值所在的行
DT <- fread('Cars93.csv')
# 灵活使用 head/tail
head(tail(DT[order(Price)], 5), 1)
38.如何计算数值列之间的 correlation score
DT <- fread('Cars93.csv')
# 用 cor 函数计算 DT 中的数值列
cor( DT[, .SD, .SDcols = which(sapply(DT, is.numeric))])
39.如何 normalize 指定的列、所有数值列
DT <- fread('Cars93.csv')
# normalize 所有数值列
head(DT[, lapply(.SD, scale), .SDcols = which(sapply(DT, is.numeric))])
# normalize 指定的列
head(DT[, scale(.SD), .SDcols= c('Price', 'RPM')] )
4.data.table 数据分析案例
40.导入并查看数据
flights <- fread('flights14.csv')
head(flights)
41.获得所有六月份从 JFK 出发的航班数据
head( flights[origin== "JFK" & month == 6] )
42.选择 arr_delay 和 dep_delay 并重命名为 到达延误 和 起飞延误
head(flights[, .('到达延误'= arr_delay, '起飞延误'= dep_delay)])
43.有多少航班的总延误时间 < 0
flights[, sum( (arr_delay+dep_delay)<0 )]
44.计算6月份从 JFK 起飞的航班的起飞延误和到达延误均值
flights[origin== "JFK" & month == 6, .('到达延误'= mean(arr_delay), '起飞延误'= mean(dep_delay))]
45.按起飞机场分组,计算航班数
flights[, .N, origin]
46.哪个机场最繁忙?哪个月份机场最繁忙?
# 最繁忙的机场
flights[, .N, origin][order(N, decreasing=T)][1]
# 最繁忙的月份
flights[, .N, month][order(N, decreasing=T)][1]
# 最繁忙的月份+机场组合前三名
flights[, .N, .(month, origin)][order(N, decreasing=T)][1:3]
47.按起飞、降落机场分组,获取 AA 航空公司的航班数
head( flights[carrier=="AA", .N, .(origin, dest) ] )
48.获取按起飞、降落延误分组的航班数
flights[, .N, .(dep_delay >0, arr_delay>0)]
49.按起飞机场、月份分组,获取 AA 航空公司的起飞、降落平均延误时间
flights[ carrier=="AA",
lapply(.SD, mean) ,
by = .(origin, month),
.SDcols = c("dep_delay", "arr_delay")
]
50.6月份哪个机场起飞延误情况最为严重?
flights[dep_delay>0
][, mean(dep_delay), .(carrier, month)
][order(V1, decreasing=T)][1]
总结
- data.table 是 R 语言用于处理数据的最佳工具
- 掌握 data.table[i,j,by] 语法