Reputation: 1297
I have the following dataframe
df <- data.frame(
Type=rep(LETTERS[1:6],3),
Level=rep(1:3,each=6),
Value=1:18)
I'd like to add 2 columns,
to end up with
> df
Type Level Value r1 r2
1 A 1 1 1.000000 1.0
2 B 1 2 2.000000 1.0
3 C 1 3 3.000000 1.0
4 D 1 4 4.000000 1.0
5 E 1 5 5.000000 1.0
6 F 1 6 6.000000 1.0
7 A 2 7 1.000000 7.0
8 B 2 8 1.142857 4.0
9 C 2 9 1.285714 3.0
10 D 2 10 1.428571 2.5
11 E 2 11 1.571429 2.2
12 F 2 12 1.714286 2.0
13 A 3 13 1.000000 13.0
14 B 3 14 1.076923 7.0
15 C 3 15 1.153846 5.0
16 D 3 16 1.230769 4.0
17 E 3 17 1.307692 3.4
18 F 3 18 1.384615 3.0
I tried a few apply
type approaches, but couldn't get it. I ended up with a double for
loop:
for(i in unique(df$Type)) {
for(j in unique(df$Level)) {
df$r1[df$Level==j & df$Type==i] <- df$Value[df$Level==j & df$Type==i]/df$Value[df$Level==j & df$Type=="A"]
df$r2[df$Level==j & df$Type==i] <- df$Value[df$Level==j & df$Type==i]/df$Value[df$Level==1 & df$Type==i]
}
}
This isn't too bad, but I'm wondering if there is a split-apply-combine approach that would do it, maybe with something in plyr
.
Upvotes: 3
Views: 358
Reputation: 89057
Since you suggested a plyr
solution:
df <- ddply(df, .(Level), transform, r1 = Value / Value[Type == "A"])
df <- ddply(df, .(Type), transform, r2 = Value / Value[Level == 1])
which I think reads nicely.
Upvotes: 2
Reputation: 42659
Create vectors first, then cbind them to the data frame:
r1 <- df$Value / df$Value[rep(df$Value[df$Type=='A'], each=length(levels(df$Type)))]
r2 <- df$Value / df$Value[seq_along(levels(df$Type))]
This assumes that the "Types" are repeated for each "Level", as in your example.
Here is the appropriate cbind() call:
cbind(df, r1, r2)
Upvotes: 1