Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assign sequential count for numerical runs

I'd like to assign a cumulative numerical value for sequential runs in a binary vector. What I have is

x = [0 0 0 1 1 0 1 1 1 0 1 0 0 0 0 0 0],

and what I would like is

y = [1 2 3 1 2 1 1 2 3 1 1 1 2 3 4 5 6].

The solution using sum/cumsum/unique/find range of functions alludes me. Any help would be greatly appreciated.

like image 365
J..S Avatar asked Jan 13 '15 10:01

J..S


People also ask

How do you find the number of runs in a sequence?

To find the number of runs, we can use rle function in R that stands for Run Length Encoding.

How do you set sequential numbers in SQL?

To number rows in a result set, you have to use an SQL window function called ROW_NUMBER() . This function assigns a sequential integer number to each result row.

How do you add sequential numbers in R?

The simplest way to create a sequence of numbers in R is by using the : operator. Type 1:20 to see how it works. That gave us every integer between (and including) 1 and 20 (an integer is a positive or negative counting number, including 0).


3 Answers

Here's a way:

a = arrayfun(@(x)(1:x), diff(find([1,diff(x),1])), 'uni', 0);
[a{:}]

The idea is to generate a list of the 'run lengths', i.e. [3,2,1,3,1,1,6] in your case, then just concatenate a bunch of vectors that count to each value in that list, i.e. cat(2, 1:3, 1:2, 1:1, 1:3.... I use arrayfun as a shortcut for reapplying the : operator and then use the comma separated list that {:} returns as a shortcut for the concatenation.

like image 191
Dan Avatar answered Oct 21 '22 23:10

Dan


(Not a one-liner, alas ...):

F = find(diff(x))+1;
y = ones(size(x));
y(F) = y(F)-diff([1,F]);
y = cumsum(y);

First, find all positions in x where there is a change; then build a vector of 1 where you substract the length of each continuous segment. At the end, take the cumsum of it.

like image 34
Bentoy13 Avatar answered Oct 21 '22 22:10

Bentoy13


Create a sparse matrix such that each run is on a different column, and then do the cumulative sum:

t = sparse(1:numel(x), cumsum([1 diff(x)~=0]), 1);
y = nonzeros(cumsum(t).*t).';

Use accumarray with a custom function to generate each increasing pattern in a different cell, and then concatenate all cells:

y = accumarray(cumsum([1 diff(x)~=0]).', 1, [], @(x) {1:numel(x).'});
y = [y{:}];
like image 1
Luis Mendo Avatar answered Oct 21 '22 22:10

Luis Mendo