根据两个相邻数字之间的差异将矢量分成组

时间:2015-11-27 13:53:45

标签: r data.table

我的虚拟输入向量如下所示:

x <- c(10, 20, 30, 70, 80, 90, 130, 190, 200)

我想要什么:为每个号码添加组因子。根据相邻号码之间的差异分配组。

示例
10到20之间的差异(绝对)是10,因此它们属于同一组 30到20之间的差异是10 - 它们属于同一组 30到70之间的差异是40 - 它们属于不同的群体。

鉴于最大差异20 想要的结果是:

x group
10     1
20     1
30     1
70     4
80     4
90     4
130    7
190    8
200    8

我的代码

library(data.table)
library(foreach)

x <- c(10, 20, 30, 70, 80, 90, 130, 190, 200)

x <- data.table(x, group = 1)
y <- nrow(x)

maxGap <- 20

g <- 1
groups <- 
foreach(i = 2:y, .combine = rbind) %do% {

    if (x[i, x] - x[i - 1, x] < maxGap) {
        g
    } else {
        g <- i
        g
    }
}

x[2:y]$group <- as.vector(groups)

我的问题
鉴于代码有效,但是对于大数据(行数> 10mil)来说太慢了。是否有更简单,更快速的解决方案(不使用循环)?

3 个答案:

答案 0 :(得分:4)

    string[] lines = File.ReadAllLines(@"StudentExamMarks.txt");

    string maxForeName = null;
    string maxSurName = null;
    var maxMark = 0;
    for (int i = 0; i < lines.Length; i++)
    {
        var tmp = lines[i].Split(new char[] { ' ', '.', ':' }, StringSplitOptions.RemoveEmptyEntries);
        if (tmp.Length == 3)
        {
            int value = int.Parse(tmp[2]);
            if (i == 0 || value > maxMark)
            {
                maxMark = value;
                maxForeName = tmp[0];
                maxSurName = tmp[1];
            }
        }
    }

答案 1 :(得分:3)

使用 data.table rleidshift函数的实现:

x <- c(10, 20, 30, 70, 80, 90, 130, 190, 200)
DT <- data.table(x)

DT[, grp := rleid(cumsum(x - shift(x,1L,0) > 20))]

给出:

> DT
     x grp
1:  10   1
2:  20   1
3:  30   1
4:  70   2
5:  80   2
6:  90   2
7: 130   3
8: 190   4
9: 200   4

解释:使用x - shift(x,1L,0)计算与先前x观察值的差异。通过将其与20(即> 20部分)进行比较,并将其包含在cumsumrleid中,可以创建游程长度。

回应@Roland的评论:如果您将rleid中的fill参数设置为shift,则可以退出-Inf - 部分:< / p>

DT[, grp := cumsum((x - shift(x, 1L, -Inf)) > 20)]

答案 2 :(得分:2)

test <- c(TRUE, diff(x) > 20) #test the differences
res <- factor(cumsum(test)) #groups
#[1] 1 1 1 2 2 2 3 4 4
#Levels: 1 2 3 4
levels(res) <- which(test) #fix levels
res
#[1] 1 1 1 4 4 4 7 8 8
#Levels: 1 4 7 8