sparklyr包:dplyr包在Spark中的用法

简介

dplyr是一个R包,用来处理R环境内外的结构化数据。dplyr使得R语言使用者更简单、一致、高效地处理数据。使用dplyr包处理spark数据集,功能包括:

  • Select, filter, and aggregate 数据
  • 可以使用窗口函数(如sample)
  • 多个数据集进行join
  • 将spark数据集加载到R内存中
    在dplyr语句中可以使用magrittr包中定义的管道连接,也支持参数的非标准评价。

1、读取数据
可以使用以下函数将数据读入spark数据集:

  • spark_read_csv:读取一个csv文件,提供兼容dplyr的数据源
  • spark_read_json:读取一个json文件,提供兼容dplyr的数据源
  • spark_read_parquet:读取一个parquet文件,提供兼容dplyr的数据源
  • copy_to:连接集群,通过copy_to函数将R中的数据集读入spark中,但在实际应用中,很少直接将R中的数据对象直接复制到spark

无论数据是什么格式,spark可以读取不同的数据源,包括HDFS (hdfs:// protocol), Amazon S3 (s3n:// protocol), 或本地文件 (file:// protocol)。每一个功能均可返回spark dataframe,且作为tbl类型使用。

整篇以Flights Data数据为例,进行说明:

library(sparklyr)
library(dplyr)
library(nycflights13)
library(ggplot2)
sc <- spark_connect()
flights <- copy_to(sc, flights, "flights")
airlines <- copy_to(sc, airlines, "airlines")
src_tbls(sc)
[1] "airlines" "flights"

2、dplyr 动词操作

  • select ~ SELECT 查询
  • filter ~ WHERE 过滤
  • arrange ~ ORDER 排序
  • summarise ~ aggregators: sum, min, sd, etc. 聚合函数
  • mutate ~ operators: +, *, log, etc. 变异计算

例如:

select(flights, year:day, arr_delay, dep_delay)
Source:   query [?? x 5]
Database: spark connection master=local app=sparklyr local=TRUE

# S3: tbl_spark
    year month   day arr_delay dep_delay
   <int> <int> <int>          
1   2013     1     1        11         2
2   2013     1     1        20         4
3   2013     1     1        33         2
4   2013     1     1       -18        -1
5   2013     1     1       -25        -6
6   2013     1     1        12        -4
7   2013     1     1        19        -5
8   2013     1     1       -14        -3
9   2013     1     1        -8        -3
10  2013     1     1         8        -2
... with more rows

其他操作类似,具体可看dlyr包相应的函数操作。

3、dplyr 的惰性
当使用数据库时,dplyr表现出的惰性:

  • 除非你明确提出要求,否则dplyr并未从数据库加载数据到R
  • dplyr将你想进行的操作步骤集中起来,然后在一个步骤中统一发送给数据库

例如:

c1 <- filter(flights, day == 17, month == 5, carrier %in% c('UA', 'WN', 'AA', 'DL'))
c2 <- select(c1, year, month, day, carrier, dep_delay, air_time, distance)
c3 <- arrange(c2, year, month, day, carrier)
c4 <- mutate(c3, air_time_hours = air_time / 60)

这一系列的操作并未实际接触数据库,直到访问数据(如打印c4)时,dplyr才会向数据库请求结果数据。

c4
Source:   query [?? x 8]
Database: spark connection master=local app=sparklyr local=TRUE

# S3: tbl_spark
    year month   day carrier dep_delay air_time distance air_time_hours
                               
1   2013     5    17      AA        -2      294     2248       4.900000
2   2013     5    17      AA        -1      146     1096       2.433333
3   2013     5    17      AA        -2      185     1372       3.083333
4   2013     5    17      AA        -9      186     1389       3.100000
5   2013     5    17      AA         2      147     1096       2.450000
6   2013     5    17      AA        -4      114      733       1.900000
7   2013     5    17      AA        -7      117      733       1.950000
8   2013     5    17      AA        -7      142     1089       2.366667
9   2013     5    17      AA        -6      148     1089       2.466667
10  2013     5    17      AA        -7      137      944       2.283333
... with more rows

4、管道连接 %>%
可以使用magrittr包中定义的%>%写更清晰的语法:

c4 <- flights %>%
  filter(month == 5, day == 17, carrier %in% c('UA', 'WN', 'AA', 'DL')) %>%
  select(carrier, dep_delay, air_time, distance) %>%
  arrange(carrier) %>%
  mutate(air_time_hours = air_time / 60)

5、分组
实现类似SQL中的group by功能:

c4 %>%
  group_by(carrier) %>%
  summarize(count = n(), mean_dep_delay = mean(dep_delay))

6、将spark数据集加载到R内存中
可以通过collect()函数将spark数据集复制到R的内存中:

carrierhours <- collect(c4)

collect()执行Spark查询,并将结果返回至R作进一步的分析和可视化:

with(carrierhours, pairwise.t.test(air_time, carrier))
ggplot(carrierhours, aes(carrier, air_time_hours)) + geom_boxplot()

另外,可以使用compute()函数将结果作为临时表存储在spark中:

compute(c4, 'carrierhours')
src_tbls(sc)

注:compute()函数是将spark中的结果作为临时表存储在spark中,如果是R内存中的数据,并不能作为临时表存储到spark中。

7、窗口函数
可以使用sample_n()和sample_frac()进行随机抽样:

  • sample_n()按照一定的数量进行随机抽样
  • sample_frac()按一定的分位数进行随机抽样
sample_n(flights, 10)
sample_frac(flights, 0.01)

sql_render()可以比较dplyr语法与它产生的SQL:

bestworst <- flights %>%
  group_by(year, month, day) %>%
  select(dep_delay) %>% 
  filter(dep_delay == min(dep_delay) || dep_delay == max(dep_delay))
sql_render(bestworst)
bestworst
 SELECT `year`, `month`, `day`, `dep_delay`
FROM (SELECT `year`, `month`, `day`, `dep_delay`, min(`dep_delay`) OVER (PARTITION BY `year`, `month`, `day`) AS `zzz22`, max(`dep_delay`) OVER (PARTITION BY `year`, `month`, `day`) AS `zzz23`
FROM (SELECT `year` AS `year`, `month` AS `month`, `day` AS `day`, `dep_delay` AS `dep_delay`
FROM `flights`) `ihpghnsvzx`) `daiwgkrgiq`
WHERE (`dep_delay` = `zzz22` OR `dep_delay` = `zzz23`)
Source:   query [?? x 4]
Database: spark connection master=local app=sparklyr local=TRUE
Groups: year, month, day

# S3: tbl_spark
    year month   day dep_delay
          
1   2013     1     5       327
2   2013     1     5       -16
3   2013     6    20       156
4   2013     6    20       -17
5   2013     1     6       -15
6   2013     1     6       202
7   2013     6    21       -15
8   2013     6    21       375
9   2013     1     7       -17
10  2013     1     7       366
... with more rows

8、多个数据集join
很少有数据分析只涉及到单个数据表,在实际中,通常需要灵活的工具将多个表结合起来分析:

inner_join(x, y, by = NULL, copy = FALSE, suffix = c(".x", ".y"), ...)

left_join(x, y, by = NULL, copy = FALSE, suffix = c(".x", ".y"), ...)

right_join(x, y, by = NULL, copy = FALSE, suffix = c(".x", ".y"), ...)

full_join(x, y, by = NULL, copy = FALSE, suffix = c(".x", ".y"), ...)

semi_join(x, y, by = NULL, copy = FALSE, ...)

anti_join(x, y, by = NULL, copy = FALSE, ...)

例如,下面三个语句是等价的:

flights %>% left_join(airlines)
flights %>% left_join(airlines, by = "carrier")
flights %>% left_join(airlines, by = c("carrier", "carrier"))

9、数据保存
通常需要将分析结果进行永久性存储,多数情况下最好的方式是使用spark_write_parquet 函数将结果保存到Parquet 文件:

spark_write_parquet(tbl, "hdfs://hdfs.company.org:9000/hdfs-path/data")

也可以使用spark_read_parquet函数将Parquet文件数据读入spark会话中:

tbl <- spark_read_parquet(sc, "data", "hdfs://hdfs.company.org:9000/hdfs-path/data")

同样的,也可以使用spark_write_csv和spark_write_json函数写入csv文件和json文件中。

你可能感兴趣的:(R,Spark)