Related
Suppose we have a matrix M
M <- matrix(c(1:9),3,3)
diag(M) <- NA
M
[,1] [,2] [,3]
[1,] NA 4 7
[2,] 2 NA 8
[3,] 3 6 NA
where each entry describes the outcomes of pairwise interactions. Each interaction of row i with column j is interepreted as "object i outperformed object j X times". Examples: Object 2 performs better than object 1 in 2 cases. Object 1 performs better than object 3 in 7 cases.
Is there a quick way to transform this matrix into an object holding this information in a format where each row fully describes the interactions between two objects? The goal is something like this:
[,1] [,2] [,3] [,4]
[1,] "OBJ1" "OBJ2" "N1" "N2"
[2,] "1" "2" "4" "2"
[3,] "1" "3" "7" "3"
[4,] "2" "3" "8" "6"
where the first two columns give the objects that are compared while columns 3 and 4 describe how often OBJ1 outperformed OBJ2 and vice versa. The interpretation of the first row is: Object 1 has outperformed Object 2 4 times, whereas Object 2 has outperformed Object 1 2 times. I have been playing around with reshape2 and aggregating without useful results so far.
Maybe you can try the code below
inds <- t(combn(dim(M)[1], 2))
Mout <- `colnames<-`(
cbind(inds, M[inds], M[inds[, 2:1]]),
do.call(paste0, rev(expand.grid(1:2, c("Obj", "N"))))
)
which gives
> Mout
Obj1 Obj2 N1 N2
[1,] 1 2 4 2
[2,] 1 3 7 3
[3,] 2 3 8 6
Another solution could be:
M <- matrix(c(1:9),3,3)
diag(M) <- NA
M1 <- M
M[upper.tri(M, diag=TRUE)] <- NA
M1[lower.tri(M1, diag=TRUE)] <- NA
R1 = reshape2::melt(M1, na.rm=TRUE, value.name="N1")
R2 = reshape2::melt(M, na.rm=TRUE, value.name="N2")
R1$N2 <- R2$N2
rownames(R1) <- NULL
Output:
> R1
Var1 Var2 N1 N2
1 1 2 4 2
2 1 3 7 3
3 2 3 8 6
I want to extract some values from a factor, but instead of having one index string i have a data.matrix containing multiple columns, all containing indexes.
I have:
f<-factor(c('a','b','c','a'))
d<-data.matrix(data.frame(t=c(1,3,2),u=c(2,3,4)))
> f[d]
[1] a c b b c a
But instead of having all return values in one vector, I would like to maintain the data.matrix structure like this:
[,1][,2]
a b
c c
b a
How is this possible i en elegant way?
I'm not sure of the definition of elegant, but you are essentially looking for dim().
You can do this in a cryptic way with dim<-(), like this:
`dim<-`(f[d], dim(d))
## [,1] [,2]
## [1,] a b
## [2,] c c
## [3,] b a
## Levels: a b c
Less cryptic would be the following (though note the slight difference in the result).
matrix(f[d], ncol = ncol(d))
## [,1] [,2]
## [1,] "a" "b"
## [2,] "c" "c"
## [3,] "b" "a"
If you're after a data.frame, then try:
as.data.frame.matrix(`dim<-`(f[d], dim(d)))
## V1 V2
## 1 a b
## 2 c c
## 3 b a
Or data.frame(matrix(f[d], ncol = ncol(d))).
I have a table
rawData <- as.data.frame(matrix(c(1,2,3,4,5,6,"a,b,c","d,e","f"),nrow=3,ncol=3))
1 4 a,b,c
2 5 d,e
3 6 f
I would like to convert to
1 2 3
4 5 6
a d f
b e
c
so far I can transpose and split the third column, however, I'm lost as to how to reconstruct a new table with the format outline above?
new = t(rawData)
for (e in 1:ncol(new)){
s<-strsplit(new[3:3,e], split=",")
print(s)
}
I tried creating new vectors for each iteration but I'm not sure how to efficiently put each one back into a dataframe. Would be grateful for any help. thanks!
You can use stri_list2matrix from the stringi package:
library(stringi)
rawData <- as.data.frame(matrix(c(1,2,3,4,5,6,"a,b,c","d,e","f"),nrow=3,ncol=3),stringsAsFactors = F)
d1 <- t(rawData[,1:2])
rownames(d1) <- NULL
d2 <- stri_list2matrix(strsplit(rawData$V3,split=','))
rbind(d1,d2)
# [,1] [,2] [,3]
# [1,] "1" "2" "3"
# [2,] "4" "5" "6"
# [3,] "a" "d" "f"
# [4,] "b" "e" NA
# [5,] "c" NA NA
You can also use cSplit from my "splitstackshape" package.
By default, it just creates additional columns after splitting the input:
library(splitstackshape)
cSplit(rawData, "V3")
# V1 V2 V3_1 V3_2 V3_3
# 1: 1 4 a b c
# 2: 2 5 d e NA
# 3: 3 6 f NA NA
You can just transpose that to get your desired output.
t(cSplit(rawData, "V3"))
# [,1] [,2] [,3]
# V1 "1" "2" "3"
# V2 "4" "5" "6"
# V3_1 "a" "d" "f"
# V3_2 "b" "e" NA
# V3_3 "c" NA NA
Is there any way to display edge weights when viewing the graph object as an edge list?
I want to do something in the spirit of:
get.edgelist(graph, attr='weight')
so as to view the edge pairings with the weights listed alongside the nodes, but that seems not to be allowed. Only way I know how to view the weights is to view the network data as an adjacency matrix. Hoping that's not the only way.
Using the example in the help page for function get.edgelist in pkg:igraph:
> cbind( get.edgelist(g) , round( E(g)$weight, 3 ))
[,1] [,2] [,3]
[1,] "a" "b" "0.342"
[2,] "b" "d" "0.181"
[3,] "b" "e" "0.403"
[4,] "b" "f" "0.841"
[5,] "d" "f" "0.997"
[6,] "e" "g" "0.029"
[7,] "a" "h" "0.17"
[8,] "b" "j" "0.69"
[9,] "g" "j" "0.422"
Another option is to use get.data.frame() from the igraph package
# create a random graph with weighted edges
g <- erdos.renyi.game(5, 5/10, directed = TRUE)
E(g)$weight <- runif(length(E(g)), 1, 5)
# pull nodes and edge weights
get.data.frame(g)
from to weight
1 1 5 4.716679
2 2 1 4.119414
3 1 2 4.535791
4 2 5 2.486553
5 3 2 4.932118
6 5 2 3.353693
7 1 3 3.003062
8 2 3 3.350118
9 1 4 2.929069
10 2 4 4.929474
11 5 4 4.333134
I was wondering about what are the ways to construct dynamic-size array in R.
For one example, I want to construct a n-vector but its dimension n is dynamically determined. The following code will work:
> x=NULL
> n=2;
> for (i in 1:n) x[i]=i;
> x
[1] 1 2
For another example, I want to construct a n by 2 matrix where the number of rows n is dynamically determined. But I fail even at assigning the first row:
> tmp=c(1,2)
> x=NULL
> x[1,]=tmp
Error in x[1, ] = tmp : incorrect number of subscripts on matrix
> x[1,:]=tmp
Error: unexpected ':' in "x[1,:"
Thanks and regards!
I think the answers you are looking for are rbind() and cbind():
> x=NULL # could also use x <- c()
> rbind(x, c(1,2))
[,1] [,2]
[1,] 1 2
> x <- rbind(x, c(1,2))
> x <- rbind(x, c(1,2)) # now extend row-wise
> x
[,1] [,2]
[1,] 1 2
[2,] 1 2
> x <- cbind(x, c(1,2)) # or column-wise
> x
[,1] [,2] [,3]
[1,] 1 2 1
[2,] 1 2 2
The strategy of trying to assign to "new indices" on the fly as you attempted can be done in some languages but cannot be done that way in R.
You can also use sparse matrices provided in the Matrix package. They would allow assignments of the form M <- sparseMatrix(i=200, j=50, x=234) resulting in a single value at row 200, column 50 and 0's everywhere else.
require(Matrix)
M <- sparseMatrix(i=200, j=50, x=234)
M[1,1]
# [1] 0
M[200, 50]
# [1] 234
But I think the use of sparse matrices is best reserved for later use after mastering regular matrices.
It is possible to dimension the array after we fill it (in a one-dimensional, vector, fashion)
Emulating the 1-dimension snippet of the question, here's the way it can be done with higher dimensions.
> x=c()
> tmp=c(1,2)
> n=6
> for (i in seq(1, by=2, length=n)) x[i:(i+1)] =tmp;
> dim(x) = c(2,n)
> x
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 1 1 1 1 1
[2,] 2 2 2 2 2 2
>
Rather than using i:(i+1) as index, it may be preferable to use seq(i, length=2) or better yet, seq(i, length=length(tmp)) for a more generic approach, as illustrated below (for a 4 x 7 array example)
> x=c()
> tmp=c(1,2,3,4)
> n=7
> for (i in seq(1, by=length(tmp), length=n))
x[seq(i, length=length(tmp))] = tmp;
> dim(x) = c(length(tmp),n)
> x
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] 1 1 1 1 1 1 1
[2,] 2 2 2 2 2 2 2
[3,] 3 3 3 3 3 3 3
[4,] 4 4 4 4 4 4 4
>
We can also obtain a similar result by re-assigning x with cbind/rbind, as follow.
> tmp=c(1,2)
> n=6
> x=rbind(tmp)
> for (i in 1:n) x=rbind(x, tmp);
> x
[,1] [,2]
tmp 1 2
tmp 1 2
tmp 1 2
tmp 1 2
tmp 1 2
tmp 1 2
tmp 1 2
Note: one can get rid of the "tmp" names (these are a side effect of the rbind), with
> dimnames(x)=NULL
You can rbind it:
tmp = c(1,2)
x = NULL
rbind(x, tmp)
I believe this is an approach you need
arr <- array(1)
arr <- append(arr,3)
arr[1] <- 2
print(arr[1])
(found on rosettacode.org)
When I want to dynamically construct an array (matrix), I do it like so:
n <- 500
new.mtrx <- matrix(ncol = 2, nrow = n)
head(new.mtrx)
[,1] [,2]
[1,] NA NA
[2,] NA NA
[3,] NA NA
[4,] NA NA
[5,] NA NA
[6,] NA NA
Your matrix is now ready to accept vectors.
Assuming you already have a vector, you pass that to the matrix() function. Notice how values are "broken" into the matrix (column wise). This can be changed with byrow argument.
matrix(letters, ncol = 2)
[,1] [,2]
[1,] "a" "n"
[2,] "b" "o"
[3,] "c" "p"
[4,] "d" "q"
[5,] "e" "r"
[6,] "f" "s"
[7,] "g" "t"
[8,] "h" "u"
[9,] "i" "v"
[10,] "j" "w"
[11,] "k" "x"
[12,] "l" "y"
[13,] "m" "z"
n = 5
x = c(1,2) %o% rep(1,n)
x
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1 1 1 1 1
# [2,] 2 2 2 2 2
x = rep(1,n) %o% c(1,2)
x
# [,1] [,2]
# [1,] 1 2
# [2,] 1 2
# [3,] 1 2
# [4,] 1 2
# [5,] 1 2