Reputation: 3
I have a long format data set, which similar like
1. ReactionTime X(a categorical variable) y(a categorical variable)
2. 1.23 * 1 * 4
3. 2.33 * 2 * 4
4. 3.45 * 3 * 5
5. 1.44 * 4 * 2
6. 1.27 * 5 * 6
7. 5.44 * 5 * 5
8. 3.22 * 7 * 4
9. 3.22 * 8 * 2
10. 3.56 * 1 * 4
and I want to covert the above dataset into a matrix with variable x on the horizontal line and variable y on the vertical line. But you can see the first and last observation share the same "cell", both of them have x variable in 1 and y variable in 4. My intention is to calculate the mean of reaction times of first and last observations and put the mean to the cell, so is there anyway I can do that? Thank you!
Upvotes: 0
Views: 77
Reputation: 269852
Try tapply
. No packages are used.
tapply(df$ReactionTime, df[c("Y", "X")], mean)
giving:
X
Y 1 2 3 4 5 7 8
2 NA NA NA 1.44 NA NA 3.22
4 2.395 2.33 NA NA NA 3.22 NA
5 NA NA 3.45 NA 5.44 NA NA
6 NA NA NA NA 1.27 NA NA
Note: df
in reproducible form is:
df <- structure(list(ReactionTime = c(1.23, 2.33, 3.45, 1.44, 1.27,
5.44, 3.22, 3.22, 3.56), X = c(1L, 2L, 3L, 4L, 5L, 5L, 7L, 8L,
1L), Y = c(4L, 4L, 5L, 2L, 6L, 5L, 4L, 2L, 4L)), .Names = c("ReactionTime",
"X", "Y"), class = "data.frame", row.names = c(NA, -9L))
Upvotes: 0
Reputation: 202
Using SQL, with the package sqldf
df = read.table(header = T, text = "ReactionTime X Y
1.23 1 4
2.33 2 4
3.45 3 5
1.44 4 2
1.27 5 6
5.44 5 5
3.22 7 4
3.22 8 2
3.56 1 4")
#.............................................................
library(sqldf)
c=data.frame(c=sort(unique(df$X)))
r=data.frame(r=sort(unique(df$Y)))
DAT=sqldf("select r.r , c.c ,
avg(ReactionTime) as M
from r cross join c
left join df
on r.r=df.Y and c.c=df.X
group by r.r, c.c
order by r.r, c.c")
M = matrix(DAT$M, nrow=dim(r)[1], ncol=dim(c)[1], byrow=TRUE)
dimnames(M)=list(r$r, c$c)
# M
# 1 2 3 4 5 7 8
# 2 NA NA NA 1.44 NA NA 3.22
# 4 2.395 2.33 NA NA NA 3.22 NA
# 5 NA NA 3.45 NA 5.44 NA NA
# 6 NA NA NA NA 1.27 NA NA
Upvotes: 0
Reputation: 202
Using Base R
df = read.table(header = T, text = "ReactionTime X Y
1.23 1 4
2.33 2 4
3.45 3 5
1.44 4 2
1.27 5 6
5.44 5 5
3.22 7 4
3.22 8 2
3.56 1 4")
c=sort(unique(df$X))
r=sort(unique(df$Y))
W=unique(df[2:3])
M=matrix(NA,ncol=length(c), nrow=length(r))
dimnames(M)=list( r , c )
for( i in 1:dim(W)[1] ){
c0=which(c==W[i,1])
r0=which(r==W[i,2])
A=which(df$X==W[i,1] & df$Y==W[i,2])
M[r0, c0] = mean(df$ReactionTime[A],na.rm = TRUE)
}
Upvotes: 0
Reputation: 121588
You are trying to reshape data from the long format to the wide format.
dcast
from the data.table
is designed for this kind of operation:
library(data.table)
dcast(data=setDT(dx),formula = X~Y,
fun.aggregate = mean,value.var = "ReactionTime",fill = 0)
# X 2 4 5 6
# 1: 1 0.00 2.395 0.00 0.00
# 2: 2 0.00 2.330 0.00 0.00
# 3: 3 0.00 0.000 3.45 0.00
# 4: 4 1.44 0.000 0.00 0.00
# 5: 5 0.00 0.000 5.44 1.27
# 6: 7 0.00 3.220 0.00 0.00
# 7: 8 3.22 0.000 0.00 0.00
Upvotes: 1
Reputation: 29095
If I understand your question correctly, the following should work:
library(dplyr); library(tidyr); library(tibble)
df %>%
# calculate mean reaction time for each cell
group_by(X, Y) %>%
summarise(ReactionTime = mean(ReactionTime)) %>%
ungroup() %>%
# spread cells (if you don't want NAs in empty cells, use the 2nd version)
spread(Y, ReactionTime) %>%
# spread(Y, ReactionTime, fill = 0) %>%
# convert to matrix with X in row names & Y in column names
remove_rownames() %>%
column_to_rownames("X") %>%
as.matrix()
2 4 5 6
1 NA 2.395 NA NA
2 NA 2.330 NA NA
3 NA NA 3.45 NA
4 1.44 NA NA NA
5 NA NA 5.44 1.27
7 NA 3.220 NA NA
8 3.22 NA NA NA
Data:
df <- read.table(header = T, text = "ReactionTime X Y
1.23 1 4
2.33 2 4
3.45 3 5
1.44 4 2
1.27 5 6
5.44 5 5
3.22 7 4
3.22 8 2
3.56 1 4")
Upvotes: 1