Sparklyr:如何计算2个Spark表之间的相关系数?

时间:2017-04-26 11:12:53

标签: r apache-spark dplyr sparkr sparklyr

我有这两个Spark表:

simx
x0: num 1.00 2.00 3.00 ...
x1: num 2.00 3.00 4.00 ...
...
x788: num 2.00 3.00 4.00 ...

simy
y0: num 1.00 2.00 3.00 ...

在两个表中,每列具有相同数量的值。表xy都分别保存在句柄simX_tblsimY_tbl中。实际数据量非常大,可能达到40GB。

我想用simx计算simy中每列的相关系数(让我们说像cor(x0, y0, 'pearson'))。

我到处搜索,我不认为有任何现成的cor功能,所以我正在考虑使用相关公式本身(就像{{ 3}})。

根据mentioned in here中的一个很好的解释,我认为使用mutate_allmutate_each效率不高,并为更大的数据量提供C stack error,所以我考虑一下使用invoke代替直接从Spark调用函数。

到目前为止,我设法到达这里:

exprs <- as.list(paste0("sum(", colnames(simX_tbl),")"))

corr_result <- simX_tbl%>%  
  spark_dataframe() %>% 
  invoke("selectExpr", exprs) %>% 
  invoke("toDF", as.list(colnames(simX_tbl))) %>% 
  sdf_register("corr_result")

计算sum中每列的simx。但后来,我意识到我还需要计算simy表,我不知道如何将两个表交互在一起(比如,在操作simy时访问simx

有没有办法以更好的方式计算相关性?或者也许只是如何与其他Spark表进行交互。

我的Spark版本是1.6.0

编辑: 我尝试使用combine中的dplyr函数:

xy_df <- simX_tbl %>% 
  as.data.frame %>%
  combine(as.data.frame(simY_tbl)) %>%
  # convert both table to dataframe, then combine. 
  # It will become list, so need to convert to dataframe again
  as.data.frame 

xydata <- copy_to(sc, xy_df, "xydata") #copy the dataframe into Spark table

但我不确定这是否是一个好的解决方案,因为:

  1. 需要加载到R内部的数据框中,我认为这对大尺寸数据来说是不实用的
  2. 尝试head句柄xydata时,列名将成为所有值的连续

    xydata %>% head
    Source:   query [6 x 790]
    Database: spark connection master=yarn-client app=sparklyr local=FALSE
    

    c_1_67027262134984_2_44919662134984_1_85728542134984_1_49317262134984_                                                                        
        1 1.670273
        2 2.449197
        3 1.857285
        4 1.493173
        5 1.576857
        6 -5.672155

1 个答案:

答案 0 :(得分:3)

我个人会回到the input dataset来解决这个问题。只是为了记录输入数据已经使用CSV阅读器加载:

df <- spark_read_csv(
  sc, path = path, name = "simData", delimiter = " ", 
  header = "false", infer_schema = "false"
) %>% rename(y = `_c0`, xs = `_c1`)

看起来或多或少像这样:

      y                                                   xs
  <chr>                                                <chr>
1 21.66     2.643227,1.2698358,2.6338573,1.8812188,3.8708665
2 35.15 3.422151,-0.59515584,2.4994135,-0.19701914,4.0771823
3 15.22  2.8302398,1.9080592,-0.68780196,3.1878228,4.6600842

现在不是将数据拆分成mutlitple表,而是让它们一起处理:

exprs <- lapply(
 0:(n - 1), 
 function(i) paste("CAST(xs[", i, "] AS double) AS x", i, sep=""))

df %>% 
  # Convert to native Spark
  spark_dataframe() %>%
  # Split and select xs, but retain y
  invoke("selectExpr", list("y", "split(xs, ',') AS  xs")) %>%
  invoke("selectExpr", c("CAST(y AS DOUBLE)", exprs)) %>%
  # Register table so we can access it from dplyr
  invoke("registerTempTable", "exploded_df")

并申请summarize_each

tbl(sc, "exploded_df") %>% summarize_each(funs(corr(., y)), starts_with("x"))
Source:   query [1 x 5]
Database: spark connection master=local[*] app=sparklyr local=TRUE

         x0         x1        x2         x3         x4
      <dbl>      <dbl>     <dbl>      <dbl>      <dbl>
1 0.8503358 -0.9972426 0.7242708 -0.9975092 -0.5571591

快速完整性检查(yx0yx4之间的关联):

cor(c(21.66, 35.15, 15.22), c(2.643227, 3.422151, 2.8302398))
[1] 0.8503358
cor(c(21.66, 35.15, 15.22), c(3.8708665, 4.0771823, 4.6600842))
[1] -0.5571591

您当然可以首先集中数据:

exploded <- tbl(sc, "exploded_df")

avgs <- summarize_all(exploded, funs(mean)) %>% as.data.frame()
center_exprs <- as.list(paste(colnames(exploded ),"-", avgs))

transmute_(exploded, .dots = setNames(center_exprs, colnames(exploded))) %>% 
  summarize_each(funs(corr(., y)), starts_with("x"))

但是it doesn't affect the result

Source:   query [1 x 5]
Database: spark connection master=local[*] app=sparklyr local=TRUE

         x0         x1        x2         x3         x4
      <dbl>      <dbl>     <dbl>      <dbl>      <dbl>
1 0.8503358 -0.9972426 0.7242708 -0.9975092 -0.5571591

如果transmute_summarize_each都导致某些问题,我们可以将中心和关联直接推送到Spark:

#Centering
center_exprs <- as.list(paste(colnames(exploded ),"-", avgs))

exploded %>%  
  spark_dataframe() %>% 
  invoke("selectExpr", center_exprs) %>% 
  invoke("toDF", as.list(colnames(exploded))) %>%
  invoke("registerTempTable", "centered")

centered <- tbl(sc, "centered")

#Correlation
corr_exprs <- lapply(
  0:(n - 1), 
  function(i) paste("corr(y, x", i, ") AS x", i, sep=""))

centered %>% 
  spark_dataframe() %>% 
  invoke("selectExpr", corr_exprs) %>% 
  invoke("registerTempTable", "corrs")

 tbl(sc, "corrs")
Source:   query [1 x 5]
Database: spark connection master=local[*] app=sparklyr local=TRUE

         x0         x1        x2         x3         x4
      <dbl>      <dbl>     <dbl>      <dbl>      <dbl>
1 0.8503358 -0.9972426 0.7242708 -0.9975092 -0.5571591

中间表当然不是必需的,这可以在我们从数组中提取数据的同时应用。