Reputation: 55
I try to aggregate data from an signal detection experiment to compute the hit rate, false alarm rate etc.
Code Cond bf1 bf2 bf3 bf4 bm1 bm2 bm3 bm4
BAX-011 3 CR FA HIT FA FR CR FA FA
My variables bf1 to bm3 are factors with the levels (hit,fa,cr,fr)
.
I want to compute the amount of hits, fa's ... for each
participant (row) but with subsets of variables (bf-items and bm-items
). What's the easiest way to perform that?
It should look like that in the end:
Code Cond bf1 bf2 bf3 bf4 bm1 bm2 bm3 bm4 bf_hits bm_hits bf_fa ...
BAX-011 3 CR FA HIT FA FR CR FA FA 1 0 2 ...
Upvotes: 0
Views: 433
Reputation: 193517
If I understand your question correctly, you probably just need to explore melt
and dcast
from the "reshape2" package. Using @zx8754's sample data, try the following:
library(reshape2)
### Make the data into a "long" format
dfL <- melt(df, id.vars=c("Code", "Cond"))
### Split the existing "variable" column.
### Here's one way to do that.
dfL <- cbind(dfL, setNames(
do.call(rbind.data.frame, strsplit(
as.character(dfL$variable), "(?=\\d)", perl=TRUE)),
c("var", "time")))
### This is what the data now look like.
head(dfL)
# Code Cond variable value var time
# 1 BAX-011 3 bf1 CR bf 1
# 2 BAX-012 3 bf1 CR bf 1
# 3 BAX-013 3 bf1 CR bf 1
# 4 BAX-011 3 bf2 FA bf 2
# 5 BAX-012 3 bf2 FA bf 2
# 6 BAX-013 3 bf2 HIT bf 2
### Use `dcast` to aggregate the data.
### The default function is "length" which is what you're looking for.
dcast(dfL, Code + Cond ~ var + value, value.var="value")
# Aggregation function missing: defaulting to length
# Code Cond bf_CR bf_FA bf_HIT bm_CR bm_FA bm_FR bm_HIT
# 1 BAX-011 3 1 2 1 1 2 1 0
# 2 BAX-012 3 1 2 1 0 2 1 1
# 3 BAX-013 3 1 1 2 0 2 1 1
From there, you can always merge
or cbind
the relevant columns together to get the full data.frame
.
To avoid being seen as a "reshape2" fanboy, here's a base R approach. I hope it also shows why I went the "reshape2" route in this case:
X <- grep("^bf|^bm", names(df))
df[X] <- lapply(df[X], as.character)
dfL <- cbind(dfL, setNames(
do.call(rbind.data.frame, strsplit(
as.character(dfL$ind), "(?=\\d)", perl=TRUE)),
c("var", "time")))
dfL$X <- paste(dfL$var, dfL$values, sep ="_")
dfA <- aggregate(values ~ Code + Cond + X, dfL, length)
reshape(dfA, direction = "wide", idvar=c("Code", "Cond"), timevar="X")
Upvotes: 1
Reputation: 56004
Try this:
#dummy data
df <- read.table(text="
Code Cond bf1 bf2 bf3 bf4 bm1 bm2 bm3 bm4
BAX-011 3 CR FA HIT FA FR CR FA FA
BAX-012 3 CR FA HIT FA FR HIT FA FA
BAX-013 3 CR HIT HIT FA FR HIT FA FA
", header=TRUE)
#count HITs per bf bm
df$bf_hit <- rowSums(df[,colnames(df)[grepl("bf",colnames(df))]]=="HIT")
df$bm_hit <- rowSums(df[,colnames(df)[grepl("bm",colnames(df))]]=="HIT")
#output
df
#Code Cond bf1 bf2 bf3 bf4 bm1 bm2 bm3 bm4 bf_hit bm_hit
#1 BAX-011 3 CR FA HIT FA FR CR FA FA 1 0
#2 BAX-012 3 CR FA HIT FA FR HIT FA FA 1 1
#3 BAX-013 3 CR HIT HIT FA FR HIT FA FA 2 1
Upvotes: 0