2017-02-16 66 views
-2

我试图用几个名字清理一个数据库,确切地说,1895971,其中许多是空白和NAs。如何优化和加快R中的循环函数

这样做,我编写,似乎工作的解决方案:

for(j in 1:length(final.cons.nom$N_COMPLETO.x)) { 

if((!is.na(final.cons.nom$N_COMPLETO.x[j]) & (final.cons.nom$N_COMPLETO.x[j] != "") & (final.cons.nom$N_COMPLETO.x[j] != " ") & length(strsplit(final.cons.nom$N_COMPLETO.x[j],' ')[[1]]) <= 3) & (length(strsplit(final.cons.nom$N_COMPLETO.x[j],' ')[[1]]) > 0)) { 

    if((is.na(final.cons.nom$NOMBRE.x[j]) | (final.cons.nom$NOMBRE.x[j] == "") | (final.cons.nom$NOMBRE.x[j] == " "))) { 
     final.cons.nom$NOMBRE.x[j] <- word(final.cons.nom$N_COMPLETO.x[j], 1)  
    } 

    if((is.na(final.cons.nom$PATERNO.x[j]) | (final.cons.nom$PATERNO.x[j] == "") | (final.cons.nom$PATERNO.x[j] == " "))) { 
     final.cons.nom$PATERNO.x[j] <- word(final.cons.nom$N_COMPLETO.x[j], 2)  
    } 

    if((is.na(final.cons.nom$MATERNO.x[j]) | (final.cons.nom$MATERNO.x[j] == "") | (final.cons.nom$MATERNO.x[j] == " "))) { 
     final.cons.nom$MATERNO.x[j] <- word(final.cons.nom$N_COMPLETO.x[j], 3)  
    } 

} 

} 

代码看起来在向量用全名N_COMPLETO.x并试图打破名字到名字(NOMBRE.x)姓氏(PATERNO.x)和姓氏(MATERNO.x),只要全名不是NA,空格或空白,具有3个或更少的单词,并且目标向量未被有效数据占据(某些名字正确地分布和分开)。

当我运行10000循环大约需要14秒,因此,整个矢量应该在不到45分钟的时间内进行分析(在非常粗糙和松散的计算中)。在这45分钟足够长的时间里,事实证明我已经将R运行了近2个小时而没有完成循环(尽管我知道它提前了)。

你有什么建议加快这种操作吗?

谢谢!

+1

在R中优化循环性能的最佳方法是消除它,以支持完全向量化的代码。 –

+0

这是我第一次尝试@JohnColeman,但是,'strsplit'没有像我应该那样操作。我会考虑这个功能。谢谢。 –

+0

另外,函数'word()'是什么?它不是基R的一部分。 –

回答

1

我最终回到了代码的矢量化版本,改变了如何使用strsplit的方法。

的向量化的解决方案,如果相当长的,但是,它可作为任何尝试这种技术的一个很好的例子:

final.cons.nom$NOMBRE.x[!is.na(final.cons.nom$N_COMPLETO.x) & 
(final.cons.nom$N_COMPLETO.x != "") & (final.cons.nom$N_COMPLETO.x != " ") & 
(sapply(strsplit(final.cons.nom$N_COMPLETO.x,' '), length) <= 3) & 
(sapply(strsplit(final.cons.nom$N_COMPLETO.x,' '), length) > 0) & 
(is.na(final.cons.nom$NOMBRE.x) | (final.cons.nom$NOMBRE.x == "") | 
(final.cons.nom$NOMBRE.x == " "))] <- 
word(final.cons.nom$N_COMPLETO.x[!is.na(final.cons.nom$N_COMPLETO.x) & 
(final.cons.nom$N_COMPLETO.x != "") & (final.cons.nom$N_COMPLETO.x != " ") & 
(sapply(strsplit(final.cons.nom$N_COMPLETO.x,' '), length) <= 3) & 
(sapply(strsplit(final.cons.nom$N_COMPLETO.x,' '), length) > 0) & 
(is.na(final.cons.nom$NOMBRE.x) | (final.cons.nom$NOMBRE.x == "") | 
(final.cons.nom$NOMBRE.x == " "))], 1) 

我特别想指出的使用strsplit的结果作为一个用于逻辑评估的向量:

sapply(strsplit(final.cons.nom$N_COMPLETO.x,' '), length) <= 3) 
+0

'word'函数是完全向量化的。您可以测试'is.na(word(final.cons.nom $ N_COMPLETO.x,4))'来查看全名是否为3个字或更少。 –

+0

太棒了!非常感谢,@JohnColeman。 –