R中用于大型复杂调查数据集的方法?

时间:2016-02-04 20:13:30

标签: r survey large-data

我不是调查方法学家或人口统计学家,但他是Thomas Lumley的R调查包的狂热粉丝。我一直在处理一个相对较大的复杂调查数据集,医疗成本和利用项目(HCUP)国家急诊部样本(NEDS)。正如卫生保健研究和质量机构所描述的那样,“来自30个州的947家医院的急诊就诊的出院数据,接近20%的美国医院ED分层样本”

2006年至2012年的完整数据集包括198,102,435次观测。我用66个变量将数据分为40,073,358个创伤性损伤相关放电。对这些数据运行简单的调查程序需要非常长的时间。我已经尝试过扔RAM(2013年末Mac Pro,3.7GHz四核,128GB(!)内存),multicore可用,subsetting,使用out-of-memory DBMS之类的MonetDB。基于设计的调查程序仍需要数小时。有时很多小时。一些适度复杂的分析需要超过15个小时。我猜测大多数计算工作都与必须是一个巨大的协方差矩阵联系在一起?

正如人们所料,使用原始数据的速度要快几个数量级。更有趣的是,根据程序,数据集如此大,未经调整的估计值可能非常接近调查结果。 (参见下面的示例)基于设计的结果显然更加精确和首选,但几小时的计算时间与秒数相比,增加的精度是不可忽视的成本。它开始看起来像是在街区周围漫步。

有没有人有这方面的经验?有没有办法优化大型数据集的R调查程序?也许更好地利用并行处理?贝叶斯方法是否使用像Stan这样的INLAHamiltonian方法可能的解决方案?或者,是否有一些未经调整的估计,特别是对于相关指标,当调查规模大且具有代表性时可以接受?

以下是几个未经调整的估算值近似于调查结果的例子。

在第一个例子中,内存中的svymean花了不到一个小时,内存需要3个多小时。直接计算花了不到一秒钟。更重要的是,点估计(svymean为34.75,未经调整为34.77)以及标准误差(0.0039和0.0037)非常接近。

    # 1a. svymean in memory 

    svydes<- svydesign(
        id = ~KEY_ED ,
        strata = ~interaction(NEDS_STRATUM , YEAR),   note YEAR interaction
        weights = ~DISCWT ,
        nest = TRUE,
        data = inj
    )

    system.time(meanAGE<-svymean(~age, svydes, na.rm=T))
         user   system  elapsed
     3082.131  143.628 3208.822 
     > meanAGE 
           mean     SE
     age 34.746 0.0039 

    # 1b. svymean out of memory
    db_design <-
        svydesign(
            weight = ~discwt ,                                   weight variable column
            nest = TRUE ,                                        whether or not psus are nested within strata
            strata = ~interaction(neds_stratum , yr) ,           stratification variable column
            id = ~key_ed ,                                          
            data = "nedsinj0612" ,                               table name within the monet database
            dbtype = "MonetDBLite" ,
            dbname = "~/HCUP/HCUP NEDS/monet"  folder location
        )

    system.time(meanAGE<-svymean(~age, db_design, na.rm=T))
          user    system   elapsed
     11749.302   549.609 12224.233
     Warning message:
     'isIdCurrent' is deprecated.
     Use 'dbIsValid' instead.
     See help("Deprecated")
           mean     SE
     age 34.746 0.0039 


    # 1.c unadjusted mean and s.e.
    system.time(print(mean(inj$AGE, na.rm=T)))
     [1] 34.77108
        user  system elapsed
       0.407   0.249   0.653
      sterr <- function(x) sd(x, na.rm=T)/sqrt(length(x))  # write little function for s.e.
     system.time(print(sterr(inj$AGE)))
     [1] 0.003706483
        user  system elapsed
       0.257   0.139   0.394 

svymean与使用svyby(近2小时)与tapply(4秒左右)的数据子集的平均值之间存在类似的对应关系:

# 2.a svyby .. svymean
system.time(AGEbyYear<-svyby(~age, ~yr, db_design, svymean, na.rm=T, vartype = c( 'ci' , 'se' )))
     user   system  elapsed
 4600.050  376.661 6594.196 
        yr      age          se     ci_l     ci_u
 2006 2006 33.83112 0.009939669 33.81163 33.85060
 2007 2007 34.07261 0.010055909 34.05290 34.09232
 2008 2008 34.57061 0.009968646 34.55107 34.59014
 2009 2009 34.87537 0.010577461 34.85464 34.89610
 2010 2010 35.31072 0.010465413 35.29021 35.33124
 2011 2011 35.33135 0.010312395 35.31114 35.35157
 2012 2012 35.30092 0.010313871 35.28071 35.32114


# 2.b tapply ... mean
system.time(print(tapply(inj$AGE, inj$YEAR, mean, na.rm=T)))
     2006     2007     2008     2009     2010     2011     2012
 33.86900 34.08656 34.60711 34.81538 35.27819 35.36932 35.38931
    user  system elapsed
   3.388   1.166   4.529

system.time(print(tapply(inj$AGE, inj$YEAR, sterr)))
        2006        2007        2008        2009        2010        2011        2012
 0.009577755 0.009620235 0.009565588 0.009936695 0.009906659 0.010148218 0.009880995
    user  system elapsed
   3.237   0.990   4.186

调查与未调整结果之间的对应关系开始以绝对计数分解,这需要编写一个吸引调查对象的小函数,并使用一小部分Lumley博士的代码对计数进行加权:

# 3.a svytotal

system.time(print(svytotal(~adj_cost, svydes, na.rm=T)))
             total       SE
adj_cost 9.975e+10 26685092
     user    system   elapsed 
10005.837   610.701 10577.755 

# 3.b "direct" calculation

SurvTot<-function(x){
    N <- sum(1/svydes$prob)
    m <- mean(x, na.rm = T)
    total <- m * N
    return(total)
}

> system.time(print(SurvTot(inj$adj_cost)))
[1] 1.18511e+11
   user  system elapsed 
  0.735   0.311   0.989 

结果不太可接受。虽然仍在调查程序确定的误差范围内。但同样,对于更精确的结果,3小时对1秒是可观的成本。

更新:2016年2月10日

感谢Severin和Anthony允许我借用你的突触。很抱歉延迟跟进,花了很少时间尝试你的建议。

Severin,您的观察结果是正确的,即Revolution Analytics / MOR构建对某些操作来说更快。看起来它与CRAN R附带的BLAS(“基本线性代数子程序”)库有关。它更精确,但速度更慢。因此,我使用专有(但免费使用mac)Apple Accelerate vecLib优化了我的机器上的BLAS,允许多线程(参见http://blog.quadrivio.com/2015/06/improved-r-performance-with-openblas.html)。这似乎缩短了一些时间,例如,从3小时到svyby / svymean到2个多小时。

安东尼,重复体重设计方法运气不佳。在我退出之前,复制品= 20的type =“bootstrap”运行约39小时; type =“BRR”返回错误“无法在一个层中使用奇数个PSU进行拆分”,当我将选项设置为small =“merge”,large =“merge”时,它会在操作系统升级之前运行几个小时巨大的叹息,耗尽了应用程序内存; type =“JKn”返回错误“无法分配大小为11964693.8 Gb的向量”

再次,非常感谢您的建议。我现在要辞职,在很长一段时间内逐步完成这些分析。如果我最终想出一个更好的方法,我会发布SO

2 个答案:

答案 0 :(得分:1)

对于大型数据集,线性化设计(svydesign)比复制设计(svrepdesign)慢得多。检查survey::as.svrepdesign中的权重函数,并使用其中一个直接进行复制设计。你不能使用线性化来完成这项任务。你最好不要使用as.svrepdesign,而是使用其中的功能。

有关将cluster=strata=fpc=直接用于重复加权设计的示例,请参阅

https://github.com/ajdamico/asdfree/blob/master/Censo%20Demografico/download%20and%20import.R#L405-L429

请注意,您还可以在此处查看每分钟的速度测试(每个事件的时间戳)http://monetdb.cwi.nl/testweb/web/eanthony/

还要注意,replicates=参数几乎100%负责设计运行的速度。所以也许做两个设计,一个用于系数(只有几个重复),另一个用于SEs(尽可能多的容忍)。以交互方式运行系数并优化白天需要的数字,然后留下需要在一夜之间运行SE计算的更大过程

答案 1 :(得分:1)

过一会儿,但在此结束循环。正如Lumley博士在上述最新评论中所提到的那样,Charco Hui将实验性sqlsurvey包复活为“ svydb”,我发现它是处理R中非常大的调查数据集的绝佳工具。请参见此处的相关文章。 :How to get svydb R package for large survey data sets to return standard errors