为此在R中运行for循环的更快方法?

时间:2016-06-25 08:36:32

标签: r

所以,这就是我的数据框架:

Product_Code      Publisher    Published_Date
AB1F                  A            2011
AB1F (A Version)      A            1999
TG1F (B Version)      B            2001
AB1Z (A Version)      A            2003
TG1F                  B            2006
GX1T                  C            2011

大约有130万行。

我要做的是对于具有相同Publisher的行,我会在Product_Code中使用grep()来查找具有相同Product Code的行,而不管它们是什么版本。并将它们设置为具有最早的Published_Date。

所以结果如下:

Product_Code      Publisher    Published_Date
AB1F                  A            1999
AB1F (A Version)      A            1999
TG1F (B Version)      B            2001
AB1Z (A Version)      A            2003
TG1F                  B            2001
GX1T                  C            2011

我试过

for (n in 1:nrow(df)) {
   A=which(grepl(df[n,1],df[,1])==TRUE & df[n,2]==df[,2])
   min.date=min(df[A,3])
   df[A,3]=min.date
}

我不确定这个for循环代码是否有效,因为我的计算机永远不会完成代码运行。

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:3)

我们可以使用data.table。转换' data.frame'到' data.table' (setDT(df1))。我们删除匹配空格的子字符串,后跟(后跟一个使用sub的字符,将其用作分组变量,if中有(个字符' Product_Code',然后我们match' A',' B'使用' Product_Code'中的子字符串,删除NAs,使用它来对“已发布的时间”进行子集,获取minelse返回&# 39; Published_Date'并将(:=)分配给' Published_Date'。

library(data.table)
setDT(df1)[, Published_Date := if(any(grep("\\(", Product_Code))) 
  min(Published_Date[na.omit(match(c("A", "B"), sub(".*\\((.).*", "\\1", Product_Code)))])
   else Published_Date , by = .(grp=sub("\\s+.*", "", Product_Code))]
     Product_Code Publisher Published_Date
#1:             AB1F         A           1999
#2: AB1F (A Version)         A           1999
#3: TG1F (B Version)         B           2001
#4: AB1Z (A Version)         A           2003
#5:             TG1F         B           2001
#6:             GX1T         C           2011

或者使用dplyrseparate' Product_Code'分为两列("产品","版本"),按"产品"分组,我们mutate' Published_Date'基于if/else条件。

library(dplyr)
library(tidyr)
df1 %>% 
    separate(Product_Code, into = c("Product", "Version"), remove=FALSE) %>%
    group_by(Product) %>% 
    mutate(Published_Date = if(all(is.na(Version))) Published_Date
          else min(Published_Date[Version == Publisher & !is.na(Version)])) %>%
    ungroup() %>%   
    select(-Product, - Version)
#      Product_Code Publisher Published_Date
#             <chr>     <chr>          <int>
#1             AB1F         A           1999
#2 AB1F (A Version)         A           1999
#3 TG1F (B Version)         B           2001
#4 AB1Z (A Version)         A           2003
#5             TG1F         B           2001
#6             GX1T         C           2011

我们也可以使用separate来避免警告消息

,而不是extract
df1 %>% 
   extract(Product_Code, into = c("Product", "Version"), 
                     "(\\S+)\\s*\\(*(\\S*).*", remove = FALSE)%>%
   group_by(Product) %>%
   mutate(Published_Date = if(all(!nzchar(Version))) Published_Date
      else min(Published_Date[Version == Publisher])) %>%
   ungroup() %>%
   select(-Product, -Version)
#     Product_Code Publisher Published_Date
#             <chr>     <chr>          <int>
#1             AB1F         A           1999
#2 AB1F (A Version)         A           1999
#3 TG1F (B Version)         B           2001
#4 AB1Z (A Version)         A           2003
#5             TG1F         B           2001
#6             GX1T         C           2011

更新

如果没有特定模式,我们可以为不具有(并且包含1个以上字词的元素创建(

df1$Product_Code <- sub("\\s+\\(*", " (", df1$Product_Code)

并使用上述代码。