Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在大型数据集上使用多个sum()优化dplyr summary()_R_Optimization_Dplyr - Fatal编程技术网

在大型数据集上使用多个sum()优化dplyr summary()

在大型数据集上使用多个sum()优化dplyr summary(),r,optimization,dplyr,R,Optimization,Dplyr,我有一个2200万行的表格,每行包含一组生命体征、一个患者ID和一个时间。我试图获得一个汇总表,其中包含每个生命体征(列)的ID和非空值的数量 我下面的代码执行并给出合理的答案,但需要花费很长时间。我想知道是否有更有效的方法来解决这个问题。有什么优化策略吗 下面的代码将ID的名称从“pcrid”转换为“pcrid”,以使生成的表与我的旧代码兼容。我还对表格进行了一些过滤。这在整个数据集上运行很快,所以这似乎不是慢的部分 下面是它如何在不同大小的数据集(使用head())下执行的: 1000行=

我有一个2200万行的表格,每行包含一组生命体征、一个患者ID和一个时间。我试图获得一个汇总表,其中包含每个生命体征(列)的ID和非空值的数量

我下面的代码执行并给出合理的答案,但需要花费很长时间。我想知道是否有更有效的方法来解决这个问题。有什么优化策略吗

下面的代码将ID的名称从“pcrid”转换为“pcrid”,以使生成的表与我的旧代码兼容。我还对表格进行了一些过滤。这在整个数据集上运行很快,所以这似乎不是慢的部分

下面是它如何在不同大小的数据集(使用head())下执行的:

  • 1000行=0.2秒
  • 10000行=1.7秒
  • 100000行=15秒
  • 1000000行=2.9分钟
  • 22000000行=42分钟
Start%
过滤器((pta==“no”| pta==“unk”)和!is.na(pta))%>%
分组依据(PCRID)%>%
总结(
n_AVPU=总和(!is.na(AVPU)),
n_SBP=总和(!is.na(SBP)),
n_DBP=sum(!is.na(DBP)),
n_HR=sum(!is.na(pulserate)),
n_RR=sum(!is.na(RR)),
n_SpO2=总和(!is.na(SpO2)),
n_EtCO2=总和(!is.na(EtCO2)),
n_CO=sum(!is.na(CO)),
n_BGL=总和(!is.na(葡萄糖)),
n_Temp=sum(!is.na(tempf)),
n_Pain=sum(!is.na(疼痛量表)),
n_GCS=总和(!is.na(GCS)))
Sys.time()-Start

我是
数据表的初学者,但我知道当有大量组需要计算时,它可以比
dplyr
有显著的性能改进

我还没有弄清楚data.table的
语法,它既可以按PCRID分组,也可以跨许多列计算非NAs的计数。为了解决这个问题,我尝试使用
dtplyr
,一种基于
dplyr
data.table
前端,并获得了一些实质性的性能改进

使用一些与您的日志大小相似的伪数据(见下图),从您的日志中进行计数需要197秒,但当我加载
数据.table
dtplyr
并重新运行时,需要77秒,减少了61%的时间,输出相同。您的结果可能会有所不同,但如果有进一步的
数据,我不会感到惊讶。表
效率可能会进一步减少这一时间

library(data.table); library(dtplyr)
vitals_fake_DT <- data.table(vitals_fake)

vitals_fake_DT %>%
  arrange(PCRID) %>% # to make output order the same way between methods
  group_by(PCRID) %>%
  summarise(
    n_AVPU = sum(!is.na(avpu)),
    n_SBP = sum(!is.na(sbp)),
    # etc.
库(data.table);图书馆(dtplyr)
生命体征\u假\u DT%
排列(PCRID)%>%#使方法之间的输出顺序相同
分组依据(PCRID)%>%
总结(
n_AVPU=总和(!is.na(AVPU)),
n_SBP=总和(!is.na(SBP)),
#等等。

包含2000万行和1000万组的假数据:

rows = 20000000
grps = 10000000 # max, somewhat less in practice
set.seed(42)
vitals_fake <- data.frame(
  PCRID = sample(1:grps, size = rows, replace = T),
  avpu = sample(c(NA, 1:10), size = rows, replace = T),
  sbp = sample(c(NA, 1:10), size = rows, replace = T),
  dbp = sample(c(NA, 1:10), size = rows, replace = T),
  pulserate    = sample(c(NA, 1:10), size = rows, replace = T),
  rr    = sample(c(NA, 1:10), size = rows, replace = T),
  spo2  = sample(c(NA, 1:10), size = rows, replace = T),
  etco2 = sample(c(NA, 1:10), size = rows, replace = T),
  co    = sample(c(NA, 1:10), size = rows, replace = T),
  glucose   = sample(c(NA, 1:10), size = rows, replace = T),
  tempf  = sample(c(NA, 1:10), size = rows, replace = T),
  painscale  = sample(c(NA, 1:10), size = rows, replace = T),
  gcs   = sample(c(NA, 1:10), size = rows, replace = T)
)
行数=20000000
grps=10000000(最大值),实际值略低
种子(42)

vitals_fake答案在很大程度上取决于数据的外观,尤其是每组有多少行

例如,对于100000个组和42行(即总共4200000行),对于
data.table
,我得到2秒,而对于
dplyr
,我得到84秒。对于只有100个组的相同总行,dt得到0.28秒,dplyr得到0.37秒

我还做了@Jon Springs的例子,每组2行,每组10000000组。我的
数据表
解决方案是339秒,我在2464秒停止了
dplyr版本。也许解决方案的一部分是得到一个更好的处理器,如@Jon:)

编辑:我认为如果有很多组,首先融合/收集数据会更快。@Jon的10000000组示例大约需要60秒。注意:为了让它恢复到广域格式,它又增加了100秒,结束时的速度是严格意义上的
数据的两倍

melt(dt, id.vars = 'ID')[!is.na(value), .N, by = .(ID, variable)]
#or to end wide
dcast(melt(dt, id.vars = 'ID')[!is.na(value), .N, by = .(ID, variable)], ID ~ variable)
下面是我使用的函数调用。注意:我使用了
summated_all()
,因为我没有能力写出所有这些列

#Assume using all columns except the ID column

#data.table
dt[, lapply(.SD, function(x) sum(!is.na(x))), by = ID]

#dplyr
tib%>%
  group_by(ID)%>%
  summarize_all(~sum(!is.na(.)))
数据:

n_groups <- 10
n_rows <- 42
n_cols <- 12

NA_prob <- 0.3

library(data.table)
library(dplyr)

set.seed(0)
dt <- data.table(ID = rep(seq_len(n_groups), each = n_rows)
           , matrix(sample(x = c(NA_integer_, 0L)
                           , size = n_rows * n_cols * n_groups
                           , replace = T
                           , prob = c(NA_prob, 1 - NA_prob))
                    , ncol = 12)
           )

tib <- as_tibble(dt)

n_组我对此进行了尝试。我认为你可以使用Hadley Wickhams multidplyr,它利用了多核的优势。您使用
分区
而不是
分组
,并在
汇总
收集
结果

我还通过使用
rename_at
更改列名和
mutate_at
在汇总数据之前创建1和0的值,使代码更加动态
dummy
如果不是NA,则创建1,否则创建0。这段代码似乎运行得很快:

# devtools::install_github("hadley/multidplyr")
library(dplyr)
library(multidplyr)
library(hablar)

vitals_all <- vitals_all.df %>% 
  rename_at(vars(-PCRID), ~paste0("n_", toupper(.))) %>% 
  mutate_at(vars(-PCRID), ~dummy_(!is.na(.))) %>% 
  partition(PCRID) %>% 
  summarise_all(~sum(.)) %>% 
  collect()
#devtools::install_github(“hadley/multidplyr”)
图书馆(dplyr)
库(多DPLYR)
图书馆(hablar)
所有生命体征%
重命名_at(vars(-PCRID),~paste0(“n_u”),toupper(.))%>%
在(vars(-PCRID),~dummy_uu(!is.na())%%>处突变
分区(PCRID)%>%
总结所有内容(~sum(%)%%>%
收集
从Jon Spring那里借来的假数据(谢谢!):

行数=20000000
grps=10000000(最大值),实际值略低
种子(42)

vitals_all.df对于许多组的问题,
数据。表
可能比
dplyr
快得多。例如,类似问题请参见此处:
# devtools::install_github("hadley/multidplyr")
library(dplyr)
library(multidplyr)
library(hablar)

vitals_all <- vitals_all.df %>% 
  rename_at(vars(-PCRID), ~paste0("n_", toupper(.))) %>% 
  mutate_at(vars(-PCRID), ~dummy_(!is.na(.))) %>% 
  partition(PCRID) %>% 
  summarise_all(~sum(.)) %>% 
  collect()
rows = 20000000
grps = 10000000 # max, somewhat less in practice
set.seed(42)
vitals_all.df <- data.frame(
  PCRID = sample(1:grps, size = rows, replace = T),
  avpu = sample(c(NA, 1:10), size = rows, replace = T),
  sbp = sample(c(NA, 1:10), size = rows, replace = T),
  dbp = sample(c(NA, 1:10), size = rows, replace = T),
  pulserate    = sample(c(NA, 1:10), size = rows, replace = T),
  rr    = sample(c(NA, 1:10), size = rows, replace = T),
  spo2  = sample(c(NA, 1:10), size = rows, replace = T),
  etco2 = sample(c(NA, 1:10), size = rows, replace = T),
  co    = sample(c(NA, 1:10), size = rows, replace = T),
  glucose   = sample(c(NA, 1:10), size = rows, replace = T),
  tempf  = sample(c(NA, 1:10), size = rows, replace = T),
  painscale  = sample(c(NA, 1:10), size = rows, replace = T),
  gcs   = sample(c(NA, 1:10), size = rows, replace = T)
)