R : Updating a vector given a set of indices - r

I have a vector (initialized to zeros) and a set of indices of that vector. For each value in indices, I want to increment the corresponding index in the vector. So, say 6 occurs twice in indices (as in the example below), then the value of the 6th element of the vector should be 2.
Eg:
> v = rep(0, 10)
> v
[1] 0 0 0 0 0 0 0 0 0 0
> indices
[1] 7 8 6 6 2
The updated vector should be
> c(0, 1, 0, 0, 0, 2, 1, 1, 0, 0)
[1] 0 1 0 0 0 2 1 1 0 0
What is the most idiomatic way of doing this without using loops?

The function tabulate is made for that
> indices = c(7,8,6,6,2);
> tabulate(bin=indices, nbins=10);
[1] 0 1 0 0 0 2 1 1 0 0

You can use rle for this:
x <- rle(sort(indices))
v[x$values] <- x$lengths
v
# [1] 0 1 0 0 0 2 1 1 0 0

Related

Alternative ways to create a repetitive vector in R

I am tasked to create the vector
0 1 0 1 0 1 0 1 0 1
using two approaches without using c() or rep() in R.
I have tried a bunch of methods, but none of them seem to work.
Here are some of my attempts (all of which have failed) -
vector(0, 1, 0, 1, 0, 1, 0, 1, 0, 1)
a<-seq(from = 0, to = 1 , by = 1)
a
replicate(5, a)
b<-1*(0:1)
do.call(cbind, replicate(5, b, simplify=FALSE))
Any help on this would be appreciated! Thank you.
We can use bitwAnd
> bitwAnd(0:9, 1)
[1] 0 1 0 1 0 1 0 1 0 1
or kronecker
> kronecker(as.vector(matrix(1, 5)), 0:1)
[1] 0 1 0 1 0 1 0 1 0 1
> kronecker((1:5)^0, 0:1)
[1] 0 1 0 1 0 1 0 1 0 1
or outer
> as.vector(outer(0:1, (1:5)^0))
[1] 0 1 0 1 0 1 0 1 0 1
Solution 1: Generalized Function my_rep()
A generalized solution my_rep() for any vector x you wish repeated n times
my_rep <- function(x, n) {
return(
# Use modulo '%%' to subscript the original vector (whose length I'll call "m"), by
# cycling 'n' times through its indices.
x[0:(length(x) * n - 1) %% length(x) + 1]
# 1 2 ... m 1 2 ... m 1 2 ... m
# | 1st cycle | | 2nd cycle | ... | nth cycle |
)
}
which can solve this case
my_rep(x = 0:1, n = 5)
# [1] 0 1 0 1 0 1 0 1 0 1
and many others
# Getting cute, to make a vector of strings without using 'c()'.
str_vec <- strsplit("a b ", split = " ")[[1]]
str_vec
# [1] "a" "b" ""
my_rep(x = str_vec, n = 3)
# [1] "a" "b" "" "a" "b" "" "a" "b" ""
Solution 2: Binary Vector of Arbitrary Length
Another quick solution, for a 0 1 0 1 ... 0 1 vector of arbitrary length l
# Whatever length you desire.
l <- 10
# Generate a vector of alternating 0s and 1s, of length 'l'.
(1:l - 1) %% 2
which yields the output:
[1] 0 1 0 1 0 1 0 1 0 1
Note
Special thanks to #Adam, who figured out 0:9 %% 2 on their own, shortly after my comment with that same solution; and who gracefully retracted their initial answer in favor of mine. :)
Exploiting boolean coercion.
+(1:10*c(-1, 1) > 0)
# [1] 0 1 0 1 0 1 0 1 0 1
Or without c().
+(1:10*(0:1*2) - 1 > 0)
# [1] 0 1 0 1 0 1 0 1 0 1
Here is a way using the apply functions.
unlist(lapply(1:5, function(x) 0:1))
# [1] 0 1 0 1 0 1 0 1 0 1
Similar but with replicate.
as.vector(replicate(5, 0:1))
# [1] 0 1 0 1 0 1 0 1 0 1
And just in case you love trig.
abs(as.integer(cos((1:10 * pi) / 2)))
# [1] 0 1 0 1 0 1 0 1 0 1
And here is one last one that I consider cheating just because. This one generalizes to any vector you want!
unlist(unname(read.table(textConnection("0 1 0 1 0 1 0 1 0 1"))))
We can use purrr::accumulate, and a simple negate(!) operation.
accumulate will perform the same operation recursively over its data argument and output all intermediate results.
In this case, it can be broken down into:
output[1] <-0
output[2] <-!output[1]
output[3] <-!output[2]
...
the output would then be c(0, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE), which is coerced to numeric.
purrr::accumulate(0:9, ~!.x)
[1] 0 1 0 1 0 1 0 1 0 1
Firstly we will make a list of given no. and then apply unlist() function on list to convert it into a vector as shown in below code:
my_list = list(0, 1, 0, 1, 0, 1, 0, 1, 0, 1)
v = unlist(my_list)
print(v)
[ 1 ] 0 1 0 1 0 1 0 1 0 1

How to refer to previous cell in a data-frame column (lagged cell), in R

I’m working in R and am trying to find a way to refer to the previous cell within a vector when that vector belongs to a data frame. By previous cell, I’m essentially hoping for a “lag” command of some sort so that I can compare one cell to the cell previous. As an example, I have these data:
A <- c(1,0,0,0,1,0,0)
B <- c(1,1,1,1,1,0,0)
AB_df <- cbind (A,B)
What I want is for a given cell in a given row, if that cell’s value is less than the previous cell’s value for the same column vector, to return a value of 1 and if not to return a value of 0. For this example, the new columns would be called “A-flag” and “B-flag” below.
A B A-flag B-flag
1 1 0 0
0 1 1 0
0 1 0 0
0 1 0 0
1 1 0 0
0 0 1 1
0 0 0 0
Any suggestions for syntax that can do this? Ideally, to just create a new column variable into an existing data-frame.
Here is one solution using dplyr package and it's lag method:
library(dplyr)
AB_df <- data.frame(A = A, B = B)
AB_df %>% mutate(A.flag = ifelse(A < lag(A, default = 0), 1, 0),
B.flag = ifelse(B < lag(B, default = 0), 1, 0))
A B A.flag B.flag
1 1 1 0 0
2 0 1 1 0
3 0 1 0 0
4 0 1 0 0
5 1 1 0 0
6 0 0 1 1
7 0 0 0 0

R How to convert vectors of number with different length into vectors of binary with fixed length

How to convert this
1,2,5,6,9
1,2
3,11
into this:
1,1,0,0,1,1,0,0,1,0,0
1,1,0,0,0,0,0,0,0,0,0
0,0,1,0,0,0,0,0,0,0,1
I thought I can read my data by adding na if the index is not exist.
Then, replace each na with zero, and each not na with one.
But I don't know how, and I searched to similar code and I didn't find
You can do:
lapply(z,tabulate,nbins=max(unlist(z)))
[[1]]
[1] 1 1 0 0 1 1 0 0 1 0 0
[[2]]
[1] 1 1 0 0 0 0 0 0 0 0 0
[[3]]
[1] 0 0 1 0 0 0 0 0 0 0 1
where z is a list of vectors:
z <- list(c(1,2,5,6,9),c(1,2),c(3,11))
I'm not sure what your original numbers are stored as, but here's a solution assuming it's a list of vectors:
nums <-list(
c(1,2,5,6,9),
c(1,2),
c(3,11)
)
maxn <- max(unlist(nums))
lapply(nums, function(x) {
binary <- numeric(maxn)
binary[x] <- 1
binary
})

Basic R, how to populate a vector with results from a function

So I have a list of coordinates that I perform a chull on.
X <- matrix(stats::rnorm(100), ncol = 2)
hpts <- chull(X)
chull would return something like "[1] 1 3 44 16 43 9 31 41". I want to then multiple X by another vector to return only the values of X that are in the result set of chull. So for example [-2.1582511,-2.1761699,-0.5796294]*[1,0,1,...] = [-2.1582511,0,-0.5796294...] would be the result. I just don't know how to populate the second vector correctly.
Y <- matrix(0, ncol = 1,nrow=50) #create a vector with nothing
# how do I fill vector y with a 1 or 0 based on the results from chull what do I do next?
X[,1] * Y
X[,2] * Y
Thanks,
To return only the values of X that are in the result set of hpts, use
> X[hpts]
## [1] 2.1186262 0.5038656 -0.4360200 -0.8511972 -2.6542077 -0.3451074 1.0771153
## [8] 2.2306497
I read it like "X such that hpts", or "the values of hpts that are in X"
Of course, these values of X are different from yours, due to my values of rnorm
To get a vector of 1s and 0s signifying results use
> Y <- ifelse(X[,1] %in% X[hpts], 1, 0)
> Y
## [1] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 0
## [44] 0 1 0 0 1 0 1

Incidence Matrix for Finding Neighbor (both left and right) in Circular Blocks (column)

Consider a matrix with r rows and c columns and containing v integers between 0 and v-1; in the following example, r=4, c=2, and v=6.
L <- c(0,1,1,2,0,1,2,3)
(x <- matrix(L,nrow=4,ncol=2,byrow = TRUE))
## 0 1
## 1 2
## 0 1
## 2 3
The goal is to generate a r*c (row) by v column incidence matrix, as follows:
each row corresponds to one element of the original matrix (in column-major order, i.e. in the example here the 4th row corresponds to x[4,1] and the 5th row corresponds to x[1,2])
find the "neighbors" above and below each element, wrapping around (cyclically) from the top to the bottom of the matrix; count the number of neighbor elements for each value of v.
For example, the first element in the matrix (x[1,1]) has neighbours 1 (below) and 2 ("above", i.e. wrapped around to the bottom of the column; thus we enter 1 in columns 2 and 3 of row 1, matching the corresponding elements of 0:(v-1). The rest of the row is set to zero:
rownames 0 1 2 3 4 5
[1] 0 1 1 0 0 0
The next element (x[2,1]) has 0 on both sides (above and below), so the first column (corresponding to 0) is set to 2, with the rest of the elements equal to zero.
[2] 2 0 0 0 0 0
The full matrix for the example above is:
rownames 0 1 2 3 4 5
[1] 0 1 1 0 0 0
[2] 2 0 0 0 0 0
[3] 0 1 1 0 0 0
[4] 2 0 0 0 0 0
[5] 0 0 1 1 0 0
[6] 0 2 0 0 0 0
[7] 0 0 1 1 0 0
[8] 0 2 0 0 0 0
The row sums are each 2.
L =c(0,1,1,2,0,1,2,3)
x=matrix(L,nrow=4,ncol=2,byrow = TRUE)
There might be a cleaner way to do this:
wrapind <- function(i,n)
ifelse((r <- i %% n) == 0, n, r)
n <- nrow(x)
v <- 6
incmat <- matrix(0,ncol=v,nrow=prod(dim(x)),
dimnames=list(NULL,0:(v-1)))
k <- 1
for (i in seq(ncol(x)))
for (j in seq(nrow(x))) {
cat(i,j,k,"\n") ## unnecessary
tt <- table(as.character(x[wrapind(c(j-1,j+1),n),i]))
incmat[k,names(tt)] <- tt
k <- k+1
}

Resources