How can I convert A
A <- c(1,2,3,4,5,6,7,8,9)
to B
B <- c(0,0,1,2,3,0,0,4,5,6,0,0,7,8,9)
I tried this:
A <-c(1,2,3,4,5,6,7,8,9)
rows <- length(A)/3
dim(a) <- c(rows,3)
B <- matrix(0,rows,2+3)
B[,3:5] <- A
c(B)
but it doesn't work.
Why not to transform B with A:
b <- rep(c(0,0,1,1,1),time=length(A)/3)
b[b==1] <- A
b
[1] 0 0 1 2 3 0 0 4 5 6 0 0 7 8 9
Assuming that A has nonzero length and has length divisible by 3:
> c(vapply(seq(length(A)/3)-1,
function(x) c(0,0,A[(x*3+1):(x*3+3)]),
numeric(3+2)
)
)
[1] 0 0 1 2 3 0 0 4 5 6 0 0 7 8 9
It's not the prettiest line of code, but something like this should work too:
as.vector(sapply(split(A, rep(1:(length(A)/3), each = 3)),
function(x) c(0, 0, x)))
# [1] 0 0 1 2 3 0 0 4 5 6 0 0 7 8 9
First, we split the vector into sets of 3, then append two zeros to each set, and reconvert it to a vector.
Update
Here is an approach that is probably similar to the process you were thinking of:
A <- c(1,2,3,4,5,6,7,8,9) # Your vector
dim(A) <- c(3, 3) # As a matrix
B <- matrix(0, nrow=5, ncol=3) # An empty matrix to fill
B[c(3:5), ] <- A # We only want to fill these rows
dim(B) <- NULL # Remove the dims to get back to a vector
B # View your handiwork
# [1] 0 0 1 2 3 0 0 4 5 6 0 0 7 8 9
Build a receiving vector to be 5/3 the length of the original and fill in the correct entires calculated with modulo arithmetic:
> bb <- vector(length= length(A)*1.67) # Will initially be logical vector
> bb[ !seq_along(bb) %% 5 %in% 1:2 ] <- A # FALSE entries coerced to 0
> bb
[1] 0 0 1 2 3 0 0 4 5 6 0 0 7 8 9
The positions at modulo remainder 3,4,and 0 get sequentially filled with the values in A.
Here's another vectorized solution that is probably more in the spirit of your earlier efforts:
> c( rbind( matrix(0, nrow=2, ncol=length(A)/3),
matrix(A, nrow=3) ) )
[1] 0 0 1 2 3 0 0 4 5 6 0 0 7 8 9
And this shows that your solution was correct except for using column indexing when you should have been using row indexing on the LHS of the matrix assignment:
> B <- matrix(0, 5, 3)
> B[3:5, ] <- A
> B
[,1] [,2] [,3]
[1,] 0 0 0
[2,] 0 0 0
[3,] 1 4 7
[4,] 2 5 8
[5,] 3 6 9
> c(B)
[1] 0 0 1 2 3 0 0 4 5 6 0 0 7 8 9
Silly function I wrote for this, with some customizable features:
PastingZeros <- function (divide = 3, data = A, amountofzeros = 2) {
B <- NULL
n <- length(data)
index <- 1:n
for (i in 1:(n / divide)) {
B <- c(B, rep(0, amountofzeros), data[index[1:divide]])
index <- index[-1:-divide]
}
return(B)
}
PastingZeros(3, A, 0)
I don't see a solution that does not assume that A has a length that is a multiple of 3, so I'll throw one:
insert.every <- function(x, insert, every)
unlist(lapply(split(x, (seq_along(x)-1) %/% every), append, x = insert),
use.names = FALSE)
insert.every(1:9, c(0,0), 3)
# [1] 0 0 1 2 3 0 0 4 5 6 0 0 7 8 9
insert.every(1:9, c(0,0), 4)
# [1] 0 0 1 2 3 4 0 0 5 6 7 8 0 0 9
Related
Let's say I have a matrix
A = [2 3 2 5 6 7 2;
1 2 5 4 5 6 7;
7 5 3 9 8 1 2];
How do I remove 2s and keep one 2 in the first row and keep only one 5 in the second row?
The result can't be a matrix anymore, because each row will have a different length. You can obtain the result as a cell array of row vectors as follows:
B = mat2cell(A, ones(size(A,1),1)); %// convert matrix to cell array of its rows
B = cellfun(#(x) unique(x,'stable'), B, 'uniformoutput', 0); %// stably remove duplicates
For your example matrix
A = [2 3 2 5 6 7 2;
1 2 5 4 5 6 7;
7 5 3 9 8 1 2];
this gives
B{1} =
2 3 5 6 7
B{2} =
1 2 5 4 6 7
B{3} =
7 5 3 9 8 1 2
If you want to find out which values are duplicates within the row, you can do something like this:
[vals, col_idx] = sort(A,2);
idx = bsxfun(#plus,(col_idx-1)*size(A,1), (1:size(A,1))');
is_duplicate(idx(:,2:end)) = vals(:,1:end-1) == vals(:,2:end);
is_duplicate = reshape(is_duplicate, size(A));
is_duplicate =
0 0 1 0 0 0 1
0 0 0 0 1 0 0
0 0 0 0 0 0 0
From there, it depends what outcome you are looking for. You could set the duplicates to NaN or some other value, or you could set them to NaN, but then shift them to the end of the row, using something like the following:
col_idx = cumsum(~is_duplicate, 2);
idx = bsxfun(#plus,(col_idx-1)*size(A,1), (1:size(A,1))');
A_new = nan(size(A));
A_new(idx(~is_duplicate)) = A(~is_duplicate);
A_new =
2 3 5 6 7 NaN NaN
1 2 5 4 6 7 NaN
7 5 3 9 8 1 2
I have an R list (docs) where its first 2 elements are as follows:
1. A. 1 2 5 6
B. 5 6 2
C. 7 8 1 2 3 5
2. A. 4 5 3
B. 1 2 3 5 4 7 8
What I want to achieve is another list with equal sizes but with zeros instead:
1. A. 0 0 0 0
B. 0 0 0
C. 0 0 0 0 0 0
2. A. 0 0 0
B. 0 0 0 0 0 0 0
I have tried:
sapply(docs, function(x) rep(0, length(x)))
but the behaviour is not the intended because it considers the size of the outer list. Could you please help me?
It appears that you have a list of lists, that is docs is a list containing the lists 1 and 2, which then contain numeric vectors. If this is the case, try the following:
# create test list
temp <- list("v1"=list("A"=1:4,"B"=5:7,"C"=1:8), "v2"=list("A"=1:3,"B"=5:10,"C"=3:8))
# get a list of zeros with the same dimension
answer <- lapply(temp, function(x) sapply(x, function(y) rep(0, length(y))))
This question already has an answer here:
Vector as column index in matrix
(1 answer)
Closed 7 years ago.
While coding in GNU Octave/MATLAB I came through this simple problem I couldn't figure out by myself: I'm trying to select some elements of a matrix by using some indexes stored in an array. Let me put it clear with an example:
Given:
A = zeros(5, 3)
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
I would like to select some elements in A matrix row-wise, by using the values in the auxiliary array B as subindices.
Ie. the following B array
B = [ 1 3 2 1 3 ]'
1
3
2
1
3
should be read as:
1 -> index '1' on first row (element [1, 1])
3 -> index '3' on second row (element [2, 3])
2 -> index '2' on third row (element [3, 2])
1 -> index '1' on fourth row (element [4, 1])
3 -> index '3' on fifth row (element [5, 3])
Therefore, if we assign value '1' to the elements selected using the aforementioned criteria, the resulting matrix would be:
1 0 0
0 0 1
0 1 0
1 0 0
0 0 1
I believe this is a simple operation and I'm convinced that there must be a way to achieve the described behaviour without having to loop across the rows in matrix A.
Thank you.
Edit: Rewrite question so that it is (hopefully) less confusing.
Your question is a bit confusing. You're saying you want to select the elements in A by using the values in the vector B as column indexes, but your example sets (not gets) new values in matrix A. I'm explaining both cases.
Consider this matrix
A = magic(5)
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
Say you want to get/set the diagonal elements of A.
Index pairs in that case are [1,1], [2,2], [3,3], [4,4] and [5,5].
To access elements as a vector, run this
A(sub2ind([5,5], (1:5)',(1:5)'))
17
5
13
21
9
To set elements run this
A(sub2ind([5,5], (1:5)',(1:5)')) = 0
0 24 1 8 15
23 0 7 14 16
4 6 0 20 22
10 12 19 0 3
11 18 25 2 0
These commands can be written as
r = 1:5
c = 1:5
A(sub2ind([max(r),max(c)], r',c'))
# to assign values
A(sub2ind([max(r),max(c)], r',c')) = 0
# and to assign different value to each index pair
A(sub2ind([max(r),max(c)], r',c')) = [20 10 50 12 99]
In your example,
r = 1:5
c = B'
A(sub2ind([max(r),max(c)], r',c')) = 1
# or simply A(sub2ind([max(r),max(B)], r',B)) = 1
1 0 0
0 0 1
0 1 0
1 0 0
0 0 1
You can read how sub2ind works here.
Apologies in advance if this question is a duplicate, or if the solution to this question is very straightforward in Matlab. I have a M x N matrix A, a 1 x M vector ind, and another vector val. For example,
A = zeros(6,5);
ind = [3 4 2 4 2 3];
val = [1 2 3];
I would like to vectorize the following code:
for i = 1 : size(A,1)
A(i, ind(i)-1 : ind(i)+1) = val;
end
>> A
A =
0 1 2 3 0
0 0 1 2 3
1 2 3 0 0
0 0 1 2 3
1 2 3 0 0
0 1 2 3 0
That is, for row i of A, I want to insert the vector val in a certain location, as specificied by the i'th entry of ind. What's the best way to do this in Matlab without a for loop?
It can be done using bsxfun's masking capability: build a mask telling where the values will be placed, and then fill those values in. In doing this, it's easier to work with columns instead of rows (because of Matlab's column major order), and transpose at the end.
The code below determines the minimum number of columns in the final A so that all values fit at the specified positions.
Your example applies a displacement of -1 with respect to ind. The code includes a generic displacement, which can be modified.
%// Data
ind = [3 4 2 4 2 3]; %// indices
val = [1 2 3]; %// values
d = -1; %// displacement for indices. -1 in your example
%// Let's go
n = numel(val);
m = numel(ind);
N = max(ind-1) + n + d; %// number of rows in A (rows before transposition)
mask = bsxfun(#ge, (1:N).', ind+d) & bsxfun(#le, (1:N).', ind+n-1+d); %// build mask
A = zeros(size(mask)); %/// define A with zeros
A(mask) = repmat(val(:), m, 1); %// fill in values as indicated by mask
A = A.'; %// transpose
Result in your example:
A =
0 1 2 3 0
0 0 1 2 3
1 2 3 0 0
0 0 1 2 3
1 2 3 0 0
0 1 2 3 0
Result with d = 0 (no displacement):
A =
0 0 1 2 3 0
0 0 0 1 2 3
0 1 2 3 0 0
0 0 0 1 2 3
0 1 2 3 0 0
0 0 1 2 3 0
If you can handle a bit of bsxfun overdose, here's one with bsxfun's adding capability -
N = numel(ind);
A(bsxfun(#plus,N*[-1:1]',(ind-1)*N + [1:N])) = repmat(val(:),1,N)
Sample run -
>> ind
ind =
3 4 2 4 2 3
>> val
val =
1 2 3
>> A = zeros(6,5);
>> N = numel(ind);
>> A(bsxfun(#plus,N*[-1:1]',(ind-1)*N + [1:N])) = repmat(val(:),1,N)
A =
0 1 2 3 0
0 0 1 2 3
1 2 3 0 0
0 0 1 2 3
1 2 3 0 0
0 1 2 3 0
I can at most read the data of a 3-way factorial design in R. But when the number of factors is more than 3, i can't read the data in R.
#2^3 design
trt=c("000","100","010","110","001","101","011","111")
m=array(trt,dim=c(2,2,2))
m
How can i read the data of 2^4 Factorial Design in R ?
Of course it depends how you will proceed with your data afterwards, but from my point of view a simple 2 dimensional data.frame should be very convenient to process afterwards plus you can generate the factorial designs rather easily:
expand.grid(a = 0:1, b = 0:1, c = 0:1, d = 0:1)
# a b c d
# 1 0 0 0 0
# 2 1 0 0 0
# 3 0 1 0 0
# 4 1 1 0 0
# 5 0 0 1 0
# 6 1 0 1 0
# 7 0 1 1 0
# 8 1 1 1 0
# 9 0 0 0 1
# 10 1 0 0 1
# 11 0 1 0 1
# 12 1 1 0 1
# 13 0 0 1 1
# 14 1 0 1 1
# 15 0 1 1 1
# 16 1 1 1 1