这里数据虽然已经没有了缺失值,但每一行数据的含义却发生了变化。原始数据中产品T01在20160303这天并没有测试,所以这一天的值应该被解释为在此之前的最后一次quality的测试值。另一个问题是两种产品都是按月测试的,但重塑后的数据框没有以固定的频率对其date。
下面方法进问题进行修正。
代码语言:javascript复制toy_tests$ym = substr(toy_tests$date, 1, 6)
toy_tests
#> # A tibble: 8 x 6
#> id date sample quality durability ym
#> <chr> <int> <int> <int> <int> <chr>
#> 1 T01 20160201 100 9 9 201602
#> 2 T01 20160302 150 10 9 201603
#> 3 T01 20160405 180 9 10 201604
#> 4 T01 20160502 140 9 9 201605
#> 5 T02 20160201 70 7 9 201602
#> 6 T02 20160303 75 8 8 201603
#> 7 T02 20160403 90 9 8 201604
#> 8 T02 20160502 85 10 9 201605
我们只提取年月信息,然后利用它进行重塑。
代码语言:javascript复制toy_quality = dcast(toy_tests, ym ~ id, value.var = "quality")
toy_quality
#> ym T01 T02
#> 1 201602 9 7
#> 2 201603 10 8
#> 3 201604 9 9
#> 4 201605 9 10
现在,两种产品每月的质量得分自然地展示出来,而且每月缺失值。
有时候,我们需要将许多列合并为1列,用于表示被测量的对象,另外用1列存储对应的结果值。下面用melt()
函数将原始数据两种测量组合到一起:
toy_tests2 = melt(toy_tests, id.vars = c("id", "ym"),
measure.vars = c("quality", "durability"),
variable.name = "measure")
toy_tests2
#> id ym measure value
#> 1 T01 201602 quality 9
#> 2 T01 201603 quality 10
#> 3 T01 201604 quality 9
#> 4 T01 201605 quality 9
#> 5 T02 201602 quality 7
#> 6 T02 201603 quality 8
#> 7 T02 201604 quality 9
#> 8 T02 201605 quality 10
#> 9 T01 201602 durability 9
#> 10 T01 201603 durability 9
#> 11 T01 201604 durability 10
#> 12 T01 201605 durability 9
#> 13 T02 201602 durability 9
#> 14 T02 201603 durability 8
#> 15 T02 201604 durability 8
#> 16 T02 201605 durability 9
这种格式正是ggplot2
所喜爱的长格式数据,我们可以来画图:
library(ggplot2)
ggplot(toy_tests2, aes(x = ym, y = value))
geom_point()
facet_grid(id ~ measure)
我们得到了按照产品id和measure分组,以ym为x轴,以value为y轴的散点图,可以清晰对比分组后两种产品质量差异(以年月)。
我们还可以用不同的颜色来表示产品,下图可以给出与上图相同的信息:
代码语言:javascript复制ggplot(toy_tests2, aes(x = ym, y = value, color = id))
geom_point() facet_grid(. ~ measure)
通过sqldf包使用SQL查询数据框
有没有一种方法,能够直接使用SQL进行数据框查询,就像数据框是关系型数据库中的表一样呢?sqldf
包给出肯定答案。该包吸收了SQLite轻量结构和易于嵌入R会话的优点,可以用下面代码安装:
install.packages("sqldf")
首先加载包:
代码语言:javascript复制library(sqldf)
#> 载入需要的程辑包:gsubfn
#> 载入需要的程辑包:proto
#> 载入需要的程辑包:RSQLite
注意加载sqldf
包时,几个依赖包会自动加载进来。sql包的实现依赖这些包,它基本上是在R和SQLite之间传输数据和转换数据类型。
读入前面使用的产品表格:
代码语言:javascript复制product_info = read_csv("../../R/dataset/product-info.csv")
#> Parsed with column specification:
#> cols(
#> id = col_character(),
#> name = col_character(),
#> type = col_character(),
#> class = col_character(),
#> released = col_character()
#> )
product_stats = read_csv("../../R/dataset/product-stats.csv")
#> Parsed with column specification:
#> cols(
#> id = col_character(),
#> material = col_character(),
#> size = col_integer(),
#> weight = col_double()
#> )
product_tests = read_csv("../../R/dataset/product-tests.csv")
#> Parsed with column specification:
#> cols(
#> id = col_character(),
#> quality = col_integer(),
#> durability = col_integer(),
#> waterproof = col_character()
#> )
toy_tests = read_csv("../../R/dataset/product-toy-tests.csv")
#> Parsed with column specification:
#> cols(
#> id = col_character(),
#> date = col_integer(),
#> sample = col_integer(),
#> quality = col_integer(),
#> durability = col_integer()
#> )
sqldf
包的神奇之处在于我们可以使用SQL语句查询工作环境中的数据框,例如:
sqldf("select * from product_info")
#> id name type class released
#> 1 T01 SupCar toy vehicle yes
#> 2 T02 SupPlane toy vehicle no
#> 3 M01 JeepX model vehicle yes
#> 4 M02 AircraftX model vehicle yes
#> 5 M03 Runner model people yes
#> 6 M04 Dancer model people no
sqldf与SQLite一样,支持简单的选择性请求。
比如选择特定列:
代码语言:javascript复制sqldf("select id, name, class from product_info")
#> id name class
#> 1 T01 SupCar vehicle
#> 2 T02 SupPlane vehicle
#> 3 M01 JeepX vehicle
#> 4 M02 AircraftX vehicle
#> 5 M03 Runner people
#> 6 M04 Dancer people
根据条件筛选记录:
代码语言:javascript复制sqldf("select id, name from product_info where released = 'yes' ")
#> id name
#> 1 T01 SupCar
#> 2 M01 JeepX
#> 3 M02 AircraftX
#> 4 M03 Runner
除了基本的数据库操作和分组统计,该包还支持查询多个数据框,比如:
代码语言:javascript复制sqldf("select * from product_info join product_stats using (id)")
#> id name type class released material size weight
#> 1 T01 SupCar toy vehicle yes Metal 120 10.0
#> 2 T02 SupPlane toy vehicle no Metal 350 45.0
#> 3 M01 JeepX model vehicle yes Plastics 50 NA
#> 4 M02 AircraftX model vehicle yes Plastics 85 3.0
#> 5 M03 Runner model people yes Wood 15 NA
#> 6 M04 Dancer model people no Wood 16 0.6
不过sqldf包的缺点也很明显:
- sqldf默认基于SQLite,因此SQLite的局限性就是该包的局限性,比如内置的分组汇总函数是有限的,而R本身的统计汇总函数要多得多
- 不方便动态编程
- SQL的限制性也限制了该包,我们难以像操作dplyr包一样用sqldf进行表格数据的操作、变换等等
如果你喜欢这个包并想用起来,阅读sqldf更多操作例子:https://github.com/ggrothendieck/sqldf#examples
学习自《R语言编程指南》,内心强烈推荐的一本书。