R: For 循环耗时过长

Posted

技术标签:

【中文标题】R: For 循环耗时过长【英文标题】:R: For loop taking too long 【发布时间】:2017-01-19 15:59:34 【问题描述】:

问题

我有一个包含 3 个变量的数据集:一个 ID 变量、一个 TIME 变量和一个数字变量 X,只有当它不为零时才会出现在数据集中,如下表所示。

    time  ID  X
238 2007  A   28
239 2008  A   80
240 2014  A   178
241 2012  B   88
242 2011  C   369
243 2003  D   28
244 2004  D   80

我希望在一个唯一的数据框中,每个 ID 都有一个 lign,并且在 2001 年至 2016 年之间的每一年,必要时 X=0。所以这将是一个如下表:

   time  ID  X
1  2001  A   0
2  2002  A   0

7  2007  A   28
8  2008  A   80

14 2014  A   178
17 2001  B   0
7  2012  B   88

我在 R 文档或此论坛中找不到任何方法

我如何进行

为了解决这个问题,我的想法是分三步进行:

1)我每个身份证号只保留一行,不管是哪一年

data2 = data%>%group_by(ID,X)%>%distinct(.keep_all = T)

这导致下表:

    time  ID  X
238 2007  A   28
241 2012  B   88
242 2011  C   369
243 2003  D   28

2)然后我复制每一行以每年进行观察

timebis = seq(from = 2001, to = 2016, by = 1)
dupl.data2 = data2[rep(1:nrow(data1), each=length(timebis)), ]
dupl.data1$X = 0

我现在每个 ID 有 16 个观察值。

3) 用双 for 循环填充 dupl.data1$X 列

i=1
j=1 
for(i in 1:length(dupl.data2$ID))
  for(j in 1:length(data$ID))
    if (dupl.data2$timebis[i]==data$time[j] & dupl.data2$ID[i]==data$ID[j]) 
       dupl.data2$X[i]=data$X[j] 
  j=j+1  

  j=1 
  i=i+1

结论

它在小型子样本上效果很好,但我的原始数据库有大约 300 000 个观察值,而带有零的数据集要大得多。 我需要提高我的代码效率或想法来解决这个问题。

谢谢

【问题讨论】:

newDf <- merge(df, expand.grid(id=unique(df$id), year=2001:2014), by=c("id", "year"), all=TRUE); df$X[is.na(df$X)] <- 0 这样的东西会起作用。 使用data.table,merge(setDT(data), setnames(data[, seq(2001, 2016), by=data$ID], c("ID", "time")), all=TRUE)。所有需要做的就是替换丢失。 【参考方案1】:

expand 获取 ID 和年份的所有组合。然后left_join再次在dataframe上的结果得到x值。

require(dplyr)
require(tidyr) 
df <- data.frame(time = sample(2001:2012,12,replace = F),
                ID = sample(LETTERS[1:3],12, replace =T),
                x = sample(10:50,12))


df %>% 
  expand(time,ID) %>% 
  left_join(df, c('time','ID')) %>% 
  mutate(x = ifelse(is.na(x),0,x))

结果:

# A tibble: 36 × 3
time     ID     x
<int> <fctr> <dbl>
2001      A     0
2001      B    39
2001      C     0
2002      A     0
2002      B     0
2002      C    24
2003      A    35
2003      B     0
2003      C     0
2004      A    47
# ... with 26 more rows

如果由于某种原因并非所有年份都在您的数据框中,您可以使用扩展自定义值。

df %>% 
  expand(time = 2001:2012,ID) %>% 
  left_join(df, c('time','ID')) %>% 
  mutate(x = ifelse(is.na(x),0,x))

【讨论】:

您和 OP 都需要澄清您正在使用的软件包,最好使用一些 library() 命令。此外,您引用Expand 然后使用expand 有点令人困惑。仅供参考,replace(x, cond, 0) 应该等同于ifelse(cond, 0, x),这可能更适合于可读性,因为 ifelse 在效率方面的表现不佳。或者,dplyr 有一些 if_else 函数。

以上是关于R: For 循环耗时过长的主要内容,如果未能解决你的问题,请参考以下文章

用“For循环”填充矩阵耗时太长

java循环一亿次耗时多久

常见的for循环优化方式

如何停止 R 中耗时过长的函数并为其提供替代方案?

你真的会写for循环吗?来看看这些常见的for循环优化方式

你真的会写for循环吗?来看看这些常见的for循环优化方式