加速循环

时间:2015-09-02 05:59:56

标签: r data.table which

使用此处设置的数据:

https://www.dropbox.com/s/gyimxbz5f3v0uq3/kfg.RData?dl=0

执行以下代码:

<script type='text/javascript'>
    var markers = [];
    var marker;

    console.log('About to setup map');

    //setup the map 
    function initialize() {

        var mapProp = {
          draggable: true,
          scrollwheel: true,
          mapTypeId: google.maps.MapTypeId.ROADMAP
        };

        map = new google.maps.Map(document.getElementById("resultmap-canvas"), mapProp);

        // show markers
        var myLatLng = {lat: -37.8757303, lng: 145.1277893};
        var marker6610 = new google.maps.Marker({
            position: myLatLng,
            map: map
        });
        marker6610.setValues( {profileid: 6610, directoryid: 2} );
        markers.push(marker6610);

        var myLatLng = {lat: -38.0034790, lng: 145.1198805};
        var marker5316 = new google.maps.Marker({
            position: myLatLng,
            map: map
        });
        marker5316.setValues( {profileid: 5316, directoryid: 2} );
        markers.push(marker5316);

        //set map bounds
        var bounds = new google.maps.LatLngBounds();
        for(i=0;i<markers.length;i++) {
           bounds.extend(markers[i].getPosition());
        }

        map.fitBounds(bounds);

    }

    //execute the map creation
    initialize();

    // trigger map resize event when map tab is displayed
    $("#mapTab").on('shown.bs.tab', function() {
        google.maps.event.trigger(map, 'resize');
    });


</script>

可行,但真实的设置超过800k行,需要很长时间。在matrix(nrow=1600,ncol=8) -> ctw for(k in 1:8){ for(i in 1:1600){ which(kfg[,9]==i) -> aj if(length(aj)!=0){ sample(kfg[aj,11],prob=kfg[aj,k],size=1) -> ctw[i,k] } ctw[i,k] } } 或其他包中有没有办法更快地完成此操作?执行data.table步骤非常缓慢。

1 个答案:

答案 0 :(得分:4)

我必须修改原始代码以检查非零概率。我还从内循环的最后一行删除了语句ctw[i,k],因为它没有效果。你的代码是

matrix(nrow=1600,ncol=8) -> ctw
for(k in 1:8){
    for(i in 1:1600){
        which(kfg[,9]==i) -> aj
        if ((length(aj)!=0) && any(kfg[aj, k] > 0)) {
            sample(kfg[aj,11],prob=kfg[aj,k],size=1) -> ctw[i,k]
        }
    }
}
ctw

我颠倒了循环的顺序,因此kfg[,9] == i只被评估一次而不是8次。我还使用length(aj) != 0对循环外的tabulate()进行了测试。我修改后的代码是

matrix(nrow=1600,ncol=8) -> ctw
which(tabulate(kfg[, 9], 1600) != 0) -> ii
for(i in ii) {
    kfg[,9] == i -> aj
    for(k in 1:8)
        if (any(kfg[aj, k] > 0))
            sample(kfg[aj,11], 1, prob=kfg[aj,k]) -> ctw[i,k]
}
ctw

对于您的样本数据,这大约快5倍。

提取样本值kfg[,11] == kfg[[11]]的向量一次,并使用概率的矩阵as.matrix(kfg[, 1:8]),而不是data.frame,要快得多。对于样本数据,将第9列上的分割提升到循环之外要快得多,并且通过在循环外进行矢量化计算以确定相关索引来避免k循环内的条件

nrow <- 1600
matrix(nrow=nrow,ncol=8) -> ctw
x <- kfg[[11]]
pr <- as.matrix(kfg[,1:8])
ajs <- split(seq_len(nrow(kfg)), factor(kfg[[9]], levels=seq_len(nrow)))
ii <- seq_along(ajs)[lengths(ajs) > 0]
for(i in ii) {
    aj <- ajs[[i]]
    kk <- which(colSums(pr[aj,, drop=FALSE]) > 0)
    for(k in kk)
        sample(x[aj], 1, prob=pr[aj,k]) -> ctw[i,k]
}
ctw

这导致5倍的加速,比原来快25倍。

为了测量速度,我将上述每一项都包含在一个函数中,例如

f0 <- function() {
    matrix(nrow=1600,ncol=8) -> ctw
    for(k in 1:8){
        for(i in 1:1600){
            which(kfg[,9]==i) -> aj
            if ((length(aj)!=0) && any(kfg[aj, k] > 0)) {
                sample(kfg[aj,11],prob=kfg[aj,k],size=1) -> ctw[i,k]
            }
        }
     }
    ctw
}

并使用了microbenchmark软件包

> library(microbenchmark)
> microbenchmark(f0(), f1(), f2(), times=10)
Unit: milliseconds
 expr       min        lq      mean    median        uq       max neval cld
 f0() 466.12527 483.43954 484.34258 483.74805 484.21627 521.19957    10   c
 f1()  92.77415  94.79052  94.99273  95.10352  95.45368  96.10641    10  b 
 f2()  17.33708  17.83257  17.87095  17.87205  18.01723  18.16400    10 a  

f1()f2()应该相同,但它们不是

> set.seed(123); res1 <- f1(); set.seed(123); res2 <- f2()
> all.equal(res1, res2)
[1] "'is.NA' value mismatch: 12096 in current 12133 in target"

调查,这是因为第9列中的值是数字,但是被视为kfg[, 9] == i,就好像它们是整数一样。例如,

> kfg[[9]][(kfg[[9]] > 28 & kfg[[9]] <= 29)]
[1] 29 29 29
> kfg[[9]][(kfg[[9]] > 28 & kfg[[9]] <= 29)] == 29
[1] FALSE FALSE FALSE

也许意图是

kfg[[9]] = round(kfg[[9]])

有了这个改变,我们有

> all.equal(res1, res2)
[1] TRUE
> identical(res1, res2)
[1] TRUE