「R」数据操作(二)

2020-07-06 17:23:05 浏览数 (1)

这里数据虽然已经没有了缺失值,但每一行数据的含义却发生了变化。原始数据中产品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()函数将原始数据两种测量组合到一起:

代码语言:javascript复制
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所喜爱的长格式数据,我们可以来画图:

代码语言:javascript复制
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会话的优点,可以用下面代码安装:

代码语言:javascript复制
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语句查询工作环境中的数据框,例如:

代码语言:javascript复制
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包的缺点也很明显:

  1. sqldf默认基于SQLite,因此SQLite的局限性就是该包的局限性,比如内置的分组汇总函数是有限的,而R本身的统计汇总函数要多得多
  2. 不方便动态编程
  3. SQL的限制性也限制了该包,我们难以像操作dplyr包一样用sqldf进行表格数据的操作、变换等等

如果你喜欢这个包并想用起来,阅读sqldf更多操作例子:https://github.com/ggrothendieck/sqldf#examples

学习自《R语言编程指南》,内心强烈推荐的一本书。

0 人点赞