如何使用R将行数据溢出到下面的其他行(使用下面提到的逻辑)

时间:2016-07-11 06:33:56

标签: r

在下面的变量中,我想按照下面提到的某个标准划分每个值: A_B是输入数据,A_Bnew是必需的输出。以下是一些要点:

  1. 输出中存在一个数据点延迟。
  2. 如果有两个连续的非零值,则按原样粘贴。
  3. 如果任何值以下都有零,那么它应该将数字除以零的数量。
  4. 分割时应考虑的最大零数为4.
  5. 最后两行可能是也可能不是非零,因为我将循环多列,这里只是一个样本。

    以下是示例输出:

       A_B   A_Bnew
     25000        0
     20000    25000
    900000    20000
     25000   900000
         0    12500
         0    12500
     10000        0
         0     5000
         0     5000
     20000        0
         0     5000
         0     5000
         0     5000
         0     5000
         0        0
     12000        0
     12000    12000
    
  6. 感谢。

1 个答案:

答案 0 :(得分:1)

我想我明白了:

df$A_Bnew <- with(rle(df$A_B),{
    nz <- which(values!=0L);
    pre0 <- values[nz[-length(nz)]+1L]==0L;
    lens <- c(ifelse(pre0,lengths[nz+1L],1L),if (nz[length(nz)]<length(values)) lengths[length(lengths)] else 0L);
    mlens <- pmin(4L,lens);
    c(rep(0L,if (nz[1L]==1L) 1L else lengths[1L]+1L),rep(rbind(values[nz],values[nz]/mlens,0L),rbind(lengths[nz]-1L,mlens,lens-mlens+c(pre0,F))));
});
df;
##       A_B A_Bnew
## 1   25000      0
## 2   20000  25000
## 3  900000  20000
## 4   25000 900000
## 5       0  12500
## 6       0  12500
## 7   10000      0
## 8       0   5000
## 9       0   5000
## 10  20000      0
## 11      0   5000
## 12      0   5000
## 13      0   5000
## 14      0   5000
## 15      0      0
## 16  12000      0
## 17  12000  12000

数据

df <- data.frame(A_B=c(25000L,20000L,900000L,25000L,0L,0L,10000L,0L,0L,20000L,0L,0L,0L,0L,0L,
12000L,12000L));

解释

nz <- which(values!=0L);

这计算rle()向量对描述的非零游程长度的索引。

pre0 <- values[nz[-length(nz)]+1L]==0L;

我们需要知道输入中的哪些非零游程长度后面跟着零的游程长度。因此我们在这里预先计算这个逻辑向量。

必须特别处理最终的非零游程长度,因此我们必须在使用前将nz的最终元素编入索引,从而将其排除在此预计算之外。因此,我们必须记住,pre0是一个逻辑向量,对应于输入中除最终非零游程之外的所有行为。

lens <- c(...,...);

如果分布长度没有限制,则计算输出向量中每个非零输入值可以分布的总长度。

我们必须分别计算&#34;一般情况&#34;,表示除最终非零游程长度以外的所有长度,以及最终非零游程长度的特定情况。一般情况是c()调用的第一个参数,具体情况是第二个。我将在下面分别描述这些内容。

请注意,如果重复的非零值(已在rle()向量对中折叠为单个游程长度),则这些长度仅描述 final 重复该非零值需要在输出向量中分布。前面的重复更简单,稍后将介绍。

ifelse(pre0,lengths[nz+1L],1L)

一般案例分支在先前完成的pre0测试。换句话说,它是分支在哪个非零游程长度之后是输入中的游程长度。

如果为true,则返回的值是后续运行长度为零的长度。这是正确的,因为当后跟一个游程长度的零时,如果对分布长度没有限制,则前一个非零输入值可以分布在整个游程长度上。

如果为false,则返回的值只是1.这是正确的,因为它必须在输入中后跟一个非零值,这意味着只有一行可以分配到它。

if (nz[length(nz)]<length(values)) lengths[length(lengths)] else 0L

具体案例涵盖了最终的非零游程。我们必须测试它是输入中的最后一个还是倒数第二个。如果倒数第二,它的输出长度将是输入中必然跟随它的零的整个最终游程长度。如果是最后一个,我们可以简单地返回零长度,因为最终非零值的最终重复从输出向量中消失。

mlens <- pmin(4L,lens);

现在我们必须计算应用分布长度限制的lens向量的修改。我们可以将pmin()用于此目的。

请注意,我们不得覆盖lens,因为稍后会需要它。因此,我们将其分配给新变量mlens

c(...,...)

支撑块中的最终语句计算所需的输出向量。我们必须组合两个部分:(1)一个或多个零的一段,由于任务的性质(即滞后于输入向量等),以及(2)其余部分,这是必需的。我将在下面分别描述这些内容。

rep(0L,if (nz[1L]==1L) 1L else lengths[1L]+1L)

在第一个非零游程长度实际上是输入向量中的第一个游程长度的情况下,我们在输出向量中只需要1个前导零。否则,第一个游程长度必须是游程长度的零,因此我们需要与游程长度一样多的前导零,再加上后续行的1。

rep(rbind(...,...,...),rbind(...,...,...))

最后一段代码派生出三元组的基本向量和一个重复计数的并行向量,以传递给rep()。每个基矢量元素将由重复矢量中的相应计数重复。我们可以使用rbind()将两个向量构建为三元组序列。这是有效的,因为矩阵如何在内存中自然地布局; 行(IOW 沿列)首先,然后列(沿行)

我将按照rbind()次调用中出现的顺序覆盖下面三元组的每个成员,同时给出基本向量和重复向量间歇性。

values[nz]
lengths[nz]-1L

第一部分介绍了输入中重复非零值的情况。对于每次重复 previous 到最后一次重复非零值,我们必须在输出向量中实例化一个对应的元素,其值将等于输入的非零值,因为它是分布不超过1行。因此,值是逐字传递的,并且长度比输入游程长度小1。

values[nz]/mlens
mlens

第二部分涵盖了在其后续行中(最终重复)非零值的分布,直至分布长度限制。我们已经将上限分布长度预先计算为mlens,因此我们可以直接将其用作重复计数。该值是非零值除以它将在其上分配的行数,IOW除以mlens

0L
lens-mlens+c(pre0,F)

最后一块是一段零,实际上满足了两个要求。

首先,在mlens小于lens的情况下,分配长度实际上限于限制的IOW,我们必须用一个或多个来补充非零值的分布零以弥补不足。此处所需的零数显然只是lens-mlens

其次,如果非零游程长度后跟一个零游程长度,我们必须实例化一个零,以完成零行程长度到后续行的滞后。我们可以简单地添加pre0来执行此操作,因为逻辑向量强制为1表示true,0表示false。但是,因为pre0由于排除了最终的非零游程长度而短缺1,所以我们必须用一个元素来补充它以覆盖最终的游程长度。此元素必须为false,因为可能跟随最终非零游程长度的零的游程长度本身不能跟随其可以滞后零的行。