I'd like to create a 2D binary matrix, but Julia uses collect in an unexpected way and gives me a 3D matrix.
using Base.Iterators
collect(product(repeat([[0, 1]], 3)...))
Output
2×2×2 Array{Tuple{Int64,Int64,Int64},3}:
[:, :, 1] =
(0, 0, 0) (0, 1, 0)
(1, 0, 0) (1, 1, 0)
[:, :, 2] =
(0, 0, 1) (0, 1, 1)
(1, 0, 1) (1, 1, 1)
Iterating over the non-collected results however in the expected
for x in product(repeat([[0, 1]], 3)...)
println(x)
end
Output
(0, 0, 0)
(1, 0, 0)
(0, 1, 0)
(1, 1, 0)
(0, 0, 1)
(1, 0, 1)
(0, 1, 1)
(1, 1, 1)
How do I collect the tuples of the iterator as a 2D matrix?
Are you looking for something like this?
julia> X = product(repeat([[0, 1]], 3)...)
Base.Iterators.ProductIterator{Tuple{Array{Int64,1},Array{Int64,1},Array{Int64,1}}}(([0, 1], [0, 1], [0, 1]))
julia> X |> flatten |> collect |> x->reshape(x, (3,:))'
8×3 LinearAlgebra.Adjoint{Int64,Array{Int64,2}}:
0 0 0
1 0 0
0 1 0
1 1 0
0 0 1
1 0 1
0 1 1
1 1 1
Note that in your particular case the rows of the final matrix just correspond to binary counting from 0 to 2^3-1 = 7. You could simply construct the result directly:
julia> reduce(vcat, digits.(0:7, base=2, pad=3)')
8×3 Array{Int64,2}:
0 0 0
1 0 0
0 1 0
1 1 0
0 0 1
1 0 1
0 1 1
1 1 1
Related
I have data that looks like this:
d <- data.frame(Item = c(1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0)
I would like to create a column where the value is based on the last time a 0 was present in the row d$item. I don't really know how to get started with something like this in R.
Expected outcome is this:
f$recent <- c(NA, 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 1, 0, 1, 2, 3, 0)
Where each row is the the most recent observation of 0 (0 = on same row, 1 = previous row, etc.)
edit: Changed row to column, was posting before coffee. Also added expected result.
You can try rle + sequence
transform(
d,
recent = with(rle(Item), sequence(lengths)) * (Item != 0)
)
which gives
Item recent
1 1 1
2 0 0
3 0 0
4 1 1
5 1 2
6 1 3
7 1 4
8 1 5
9 1 6
10 0 0
11 0 0
12 1 1
13 0 0
14 1 1
15 1 2
16 1 3
17 0 0
You can do this, with sequence. It calculate the distance to the latest 1.
dif <- diff(c(which(d$Item == 1), length(d$Item) + 1))
sequence(dif, 0)
#[1] 0 1 2 0 0 0 0 0 0 1 2 0 1 0 0 0 1
Edit:
dif <- diff(c(1, which(d$Item != 1), length(d$Item) + 1))
sequence(dif, 0)
#[1] 0 0 0 1 2 3 4 5 6 0 0 1 0 1 2 3 0
Given the variable
a <- c(1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0)
I would like to mark the last non-zero value to produce a variable that takes value of 0 before the benchmark and 1 after it. In this case
b <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1)
A simple command that allows to mark the last non-zero value of a a column is
tail(which(a!=0),1)
But how to create the variable I need conditional on such benchmark? Any help would be much appreciated!
One option could be:
+(cumsum(a) == max(cumsum(a)))
[1] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1
Or:
+(cumsum(a) == sum(a))
We can use which to get the position, index where a is 1, wrap with max to return the last position, create a logical vector with sequence of 'a' and coerce to binary (+)
+(seq_along(a) >= max(which(a == 1)))
#[1] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1
Or use Position
+(seq_along(a) >= Position(function(x) x == 1, a, right = TRUE))
I have a vector of 1s and 0s. I would like to replace the 1s with its "spot" in the vector.
For example I would like to change
x = c(1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1)
to
1 1 1 0 2 2 2 0 0 3 0 4
The numbers of 1s and 0s in a row can change.
Here is one way to do it...
x = c(1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1)
x[x==1] <- cumsum(c(x[1], diff(x)) == 1)[x==1]
x
[1] 1 1 1 0 2 2 2 0 0 3 0 4
Another way with rle
x * with(rle(x), rep(cumsum(values), lengths))
#[1] 1 1 1 0 2 2 2 0 0 3 0 4
We create a run-length sequence of x and repeat cumsum of values lengths time and multiply it by x so that 0's remain as 0's and only 1's are changed.
Here is an option with rle and inverse.rle
inverse.rle(within.list(rle(x), values[values==1] <- seq_along(values[values==1])))
#[1] 1 1 1 0 2 2 2 0 0 3 0 4
Or an option using rleid from data.table
library(data.table)
x1 <- rleid(x)
x1[x!= 0] <- rleid(x1[x!=0])
x1 * x
#[1] 1 1 1 0 2 2 2 0 0 3 0 4
Is there a smart way to generate a list like the one below in R using perhaps lapply() or other more extrapolable procedures?
ones = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
twos = c(1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1)
threes = c(1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0)
fours = c(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0)
fives = c(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
l = list(ones, twos, threes, fours)
[[1]]
[1] 1 1 1 1 1 1 1 1 1 1 1
[[2]]
[1] 1 0 1 0 1 0 1 0 1 0 1
[[3]]
[1] 1 0 0 1 0 0 1 0 0 1 0
[[4]]
[1] 1 0 0 0 1 0 0 0 1 0 0
These correspond to polynomials coefficients in generating functions for partitions.
The first list is for ones and so the counting is in steps of 1 integer at a time; hence the vector 1,1,1,1,1,1,1,... In the entry [[2]] we have the twos, and we are counting by 2's starting at 0, skipping the 1 (coded as 0). In [[3]] we are counting by 3's: zero, three, six, nine, etc.
A fairly straightforward way in base R is
lapply(seq(0L, 5L), function(i) rep(c(1L, integer(i)), length.out=11L))
[[1]]
[1] 1 1 1 1 1 1 1 1 1 1 1
[[2]]
[1] 1 0 1 0 1 0 1 0 1 0 1
[[3]]
[1] 1 0 0 1 0 0 1 0 0 1 0
[[4]]
[1] 1 0 0 0 1 0 0 0 1 0 0
[[5]]
[1] 1 0 0 0 0 1 0 0 0 0 1
seq(0L, 5L) produces the vector 0 through 5, an equivalent would be seq_len(5L)-1L, which is faster for creation of large vectors.
c(1L, integer(i)) produces the inner, repeated part of the 0-1 vectors, which rep repeats according to the desired length (here 11) using the length.out argument.
lapply and function(i) allow the number of 0s to increase as we loop through the vector.
I have a vector that gives presence/absence of an event (insurgency in this case) over time, and I'd like to create another vector that gives onset of the event, i.e.:
occurrence <- c(1, 1, 0, 0, 1, 0, 0, 1, 1, 1)
onset <- c(0, 0, 0, 0, 1, 0, 0, 1, 0, 0)
The following loop will get what I need:
answer <- 0
for (t in 2:length(occurrence) {
answer[t] <- ifelse((occurrence[t]-occurrence[t-1])==1, 1, 0)
}
> answer
[1] 0 0 0 0 1 0 0 1 0 0
Is there an easier way of doing this?
Thanks.
Use pmax() and diff():
c(NA, pmax(0, diff(occurrence)))
[1] NA 0 0 0 1 0 0 1 0 0
This works because diff() calculates the difference between successive elements, resulting in 1 for every start. Then you need to remove the 0 and -1 values. pmax is a parallel version of max() and is handy to change all -1s to zero
diff(occurrence)
[1] 0 -1 0 1 -1 0 1 0 0
You can compare the prior time interval to the current one and chose those where 0 is followed by one with this code:
> c(0, as.numeric(occurrence[-length(occurrence)] == 0 & occurrence[-1]==1) )
[1] 0 0 0 0 1 0 0 1 0 0
(I padded it with a leading 0 because you didn't want leading occurrence:1's to be counted as new events.)