(Sorry about the poorly made title, wasn't sure how to phrase my question in a single sentence.)
I have a data.table of matches that is sorted chronologically, with P1 representing player1, P2 representing player2, and Res representing whether P1 won ("w") or drew ("d") against P2.
EDIT: a, b, and c in the P1 and P2 columns represent individual players. Think of them as Alice, Bob, and Charlie.
DT <- data.table(time = 1:10,
P1 = c("a", "a", "b", "b", "b", "a", "a", "b", "a", "c"),
Res = c("d", "w", "w", "w", "w", "w", "d", "d", "w", "w"),
P2 = c("b", "c", "c", "a", "a", "c", "c", "a", "b", "b"))
I performed the following operations to count at the time of the match, how many wins P1 had (wins1) and how many losses P2 had (loss2).
DT[, wins1 := shift(cumsum(Res == "w"), 1, fill=0L), by=P1]
DT[, loss2 := shift(cumsum(Res == "w"), 1, fill=0L), by=P2]
I am trying to create the columns for wins2, loss1, draw1, and draw2.
That is, I right now have how many wins P1 had at the time of their match against P2, but I do not know how many losses they had. Hope that makes sense. I'm sure the method to creating these columns are all similar, so if I can make one I should be able to make them all.
The final table should look like the following:
time P1 Res P2 wins1 loss1 draw1 wins2 loss2 draw2
1: 1 a d b 0 0 0 0 0 0
2: 2 a w c 0 0 1 0 0 0
3: 3 b w c 0 0 1 0 1 0
4: 4 b w a 1 0 1 1 0 1
5: 5 b w a 2 0 1 1 1 1
6: 6 a w c 1 2 1 0 2 0
7: 7 a d c 2 2 1 0 3 0
8: 8 b d a 3 0 1 2 2 2
9: 9 a w b 2 2 2 3 0 1
10: 10 c w b 0 3 1 3 1 1
Related
set0 <- data.frame(A = c("A", "B", "C", "D", "A", "B", "C", "D", "A", "B"),
B = c("E", "F", "G", "H", "I", "E", "F", "G", "H", "I"))
set0 <- table(set0)
result:
> set0
B
A E F G H I
A 1 0 0 1 1
B 1 1 0 0 1
C 0 1 1 0 0
D 0 0 1 1 0
I know that when I want to change the column order I can use the following:
set0 <- set0[, c(5, 4, 3, 2, 1)]
The above makes it possible to change the order of the column in any way I like.
I am looking for something that makes it possible to do the exact same but for the rownames.
Any ideas?
In the brackets, columns are defined to the right of the comma (that what you did). In case you didn't know yet, rows are defined to the left of the comma. So you can use one of these approaches that you like best:
set0[c(4, 3, 2, 1), ]
set0[4:1, ]
set0[rev(seq(nrow(set0))), ]
set0[c("D", "C", "B", "A"), ]
set0[rev(rownames(set0)), ]
# B
# A E F G H I
# D 0 0 1 1 0
# C 0 1 1 0 0
# B 1 1 0 0 1
# A 1 0 0 1 1
You can use factor to define the order, e.g.,
table(
transform(
set0,
A = factor(A, levels = sort(unique(A), decreasing = TRUE))
)
)
which gives
B
A E F G H I
D 0 0 1 1 0
C 0 1 1 0 0
B 1 1 0 0 1
A 1 0 0 1 1
I have a data frame of the following way
dat <- data.frame(A=c("D", "A", "D", "B"), B=c("B", "B", "D", "R"), C=c("A", "D", "C", ""), D=c("D", "C", "A", "A"))
My idea is to create a matrix with this information, based on the number of occasions that each column variable refers to the other columns (and ignore when referring to other things that are not in one of the columns (e.g. "R")). So I want to fill the following matrix:
n <- ncol(dat)
names_d <- colnames(dat)
mat <- matrix(0, nrow=n, ncol=n)
rownames(mat) <- names_d
colnames(mat) <- names_d
So in the end, I would have something like this:
A B C D
A 1 1 0 2
B 0 2 0 1
C 1 0 1 1
D 2 0 1 1
Which would be the most efficient way of doing this in R?
You can try the code below
> t(sapply(dat, function(x) table(factor(x, levels = names(dat)))))
A B C D
A 1 1 0 2
B 0 2 0 1
C 1 0 1 1
D 2 0 1 1
or
> t(xtabs(~., subset(stack(dat), values != "")))
values
ind A B C D
A 1 1 0 2
B 0 2 0 1
C 1 0 1 1
D 2 0 1 1
Another option is stack with table
table(subset(stack(dat), nzchar(values) & values != 'R'))
I am having trouble naming a data frame I reshaped. Using just reshape, I get the wrong titles, so I tried to name them myself but I cannot get the right names in the right spots.
df<-data.frame(color=rep(c("red", "blue", "green"), 10), letter=c(letter=c("a", "b", "c", "d", "e", "b", "c", "d", "e", "f", "c", "d", "e", "f", "g", "d", "e", "f", "g", "h", "e", "b", "c", "d", "e", "f", "c", "d", "e", "f"))
b<-as.data.frame(table(df))
c<-reshape(b, direction="wide", idvar="color", timevar="letter")
color Freq.a Freq.b Freq.c Freq.d Freq.e Freq.f Freq.g Freq.h
1 blue 0 1 2 1 3 2 0 1
2 green 0 1 2 2 2 2 1 0
3 red 1 1 1 3 2 1 1 0
To get rid of the "Freq.", I added used names but this didn't give the right numbers for the column names. This happens for anything I name for the first column.
names(c)<-c("color", unique(b$letter))
color 1 2 3 4 5 6 7 8
1 blue 0 1 2 1 3 2 0 1
2 green 0 1 2 2 2 2 1 0
3 red 1 1 1 3 2 1 1 0
I tried just unique without concatenating something for the first column, and the correct numbers are column names, but obviously they are in the wrong place. How can I get the right unique values over the correct columns?
names(c)<-unique(b$letter)
a b c d e f g h NA
1 blue 0 1 2 1 3 2 0 1
2 green 0 1 2 2 2 2 1 0
3 red 1 1 1 3 2 1 1 0
your b$letter column is a factor (unique(b$letter) will also be a factor), hence when being concatenated with a character, R implicitly coerces its "values" (not "levels") to character, giving you numbers.
df <- data.frame(color=rep(c("red", "blue", "green"), 10),
letter=c(letter=c("a", "b", "c", "d", "e",
"b", "c", "d", "e", "f",
"c", "d", "e", "f", "g",
"d", "e", "f", "g", "h",
"e", "b", "c", "d", "e",
"f", "c", "d", "e", "f")))
b <- as.data.frame(table(df))
c <- reshape(b, direction="wide", idvar="color", timevar="letter")
You can easily verify this by comparing the following:
> unique(b$letter)
[1] a b c d e f g h
Levels: a b c d e f g h
> class(unique(b$letter))
[1] "factor"
> as.character(unique(b$letter))
[1] "a" "b" "c" "d" "e" "f" "g" "h"
> class(as.character(unique(b$letter)))
[1] "character"
To solve this, it's as simple as using the second version:
names(c) <- c("color", as.character(unique(b$letter)))
Alternatively, you can also use sub to remove "Freq." from names(c) (which IMO is a safer and easier approach):
names(c) <- sub('^Freq\\.', '', names(c))
Result:
color a b c d e f g h
1 blue 0 1 2 1 3 2 0 1
2 green 0 1 2 2 2 2 1 0
3 red 1 1 1 3 2 1 1 0
Is this what you mean?
> setNames(reshape(b, timevar="numbers", idvar="color", direction="wide"),
c("Name", unique(b$numbers)))
Name 1 2 3 4 5 6 7 8
1 blue 0 1 2 1 3 2 0 1
2 green 0 1 2 2 2 2 1 0
3 red 1 1 1 3 2 1 1 0
I have data that looks similar to these two adjacency matrices:
data1999 <- data.frame(node1=c("A", "A", "B", "D", "B", "C", "D"),
node2=c("A", "A", "D", "B", "B", "C", "D"),
link=c(1, 1, 1, 1, 1, 1, 1),
stringsAsFactors = FALSE)
adj.m1999 <- reshape2::acast(data1999, node1 ~ node2)
> adj.m1999
A B C D
A 2 0 0 0
B 0 1 0 1
C 0 0 1 0
D 0 1 0 1
data2000 <- data.frame(node1=c("A", "A", "B", "C", "D", "C", "D"),
node2=c("A", "A", "B", "C", "D", "D", "C"),
link=c(1, 1, 1, 1, 1, 1, 1),
stringsAsFactors = FALSE)
adj.m2000 <- reshape2::acast(data2000, node1 ~ node2)
> adj.m2000
A B C D
A 2 0 0 0
B 0 1 0 0
C 0 0 1 1
D 0 0 1 1
Note that in 1999, node D and B have a link.
Note that in 2000, node D and C have a link.
Based on this information, I want to construct a new adjacency matrix (with all the nodes of my 2000 data) in which B-D and D-B have a value of 1 while the rest has a zero:
> result
A B C D
A 0 0 0 0
B 0 0 1 0
C 0 1 0 0
D 0 0 0 0
In my real-life data, data 1999 can have additional nodes that don't return in 2000 and vice versa.
Any ideas?
In graph theory, the product of two adjacency matices m1 and m2 gives in position (i,j) the number of ways to go from i to j, going first through m1 then through m2. This is related to what you want but not exactly the same as, if we do adj.m1999 %*% adj.m2000, we get:
A B C D
A 4 0 0 0
B 0 1 1 1
C 0 0 1 1
D 0 1 1 1
So for example, you can go from C to D in one way, and that would be C -> C, followed by C -> D.
In your example, you don't take into account links (or edges) that are on the diagonal, and also your graph is not directed, so, if I understand correctly what you want, you could do:
## First make sure that you have in adj.m1999 only nodes that appear in adj.m2000:
adj.m1999 = adj.m1999[row.names(adj.m1999) %in% row.names(adj.m2000),colnames(adj.m1999) %in% colnames(adj.m2000)]
## Then turn both diagonals into zeros:
diag(adj.m1999) = 0
diag(adj.m2000) = 0
## Finally, get the sum of the two products
res = adj.m1999 %*% adj.m2000 + adj.m2000 %*% adj.m1999
A B C D
A 0 0 0 0
B 0 0 1 0
C 0 1 0 0
D 0 0 0 0
Assume
xx.1 <- c("a", "b", "d")
xx.2 <- c("a", "d", "e")
xx.3 <- c("b", "e", "d", "f")
How to make a boolean matrix as this:
xx.1 xx.2 xx.3
a 1 1 NA
b 1 NA 1
d 1 1 1
e NA 1 1
f NA NA 1
Try table and stack:
table(stack(list(xx.1 = xx.1, xx.2 = xx.2, xx.3 = xx.3)))
# ind
# values xx.1 xx.2 xx.3
# a 1 1 0
# b 1 0 1
# d 1 1 1
# e 0 1 1
# f 0 0 1
More conveniently, you can try:
table(stack(mget(ls(pattern = "xx"))))