我有一个相当大的数据框,有一个数字列和一堆因子。其中一个因素只有两个值。我想生成一个新的,较小的数据框,将数值变量除以同一列中的另一个值。
示例数据:
set.seed(1)
V1 <- rep(c("a","b"), each =8)
V2 <- 1:4
V3 <- rep(c("High","Low"), each=4)
V4 <- rnorm(16)
foo <- data.frame(V1,V2,V3,V4)
这给了我以下数据框:
V1 V2 V3 V4
1 a 1 High -0.62645381
2 a 2 High 0.18364332
3 a 3 High -0.83562861
4 a 4 High 1.59528080
5 a 1 Low 0.32950777
6 a 2 Low -0.82046838
7 a 3 Low 0.48742905
8 a 4 Low 0.73832471
9 b 1 High 0.57578135
10 b 2 High -0.30538839
11 b 3 High 1.51178117
12 b 4 High 0.38984324
13 b 1 Low -0.62124058
14 b 2 Low -2.21469989
15 b 3 Low 1.12493092
16 b 4 Low -0.04493361
我想生成一个较小的数据帧,将V4(高)除以匹配的V4(低)
V1 V2 V4
1 a 1 -1.901181 #foo[1,4]/foo[5,4]
2 a 2 -0.223827 #foo[2,4]/foo[6,4]
...
问题是我的真实数据比这更麻烦。我做知道V3经常重复,每个Low都有一个High,但是V2和V1 不会像我在这里演示的那样经常重复。它们不是非常不规则,但有一些下降值(即b3Low和b3High可能已被删除)
我假设我不得不以某种方式重构我的数据框,但我不知道从哪里开始。提前谢谢。
答案 0 :(得分:1)
以下是使用dplyr
和reshape2
的选项:
library(dplyr)
library(reshape2)
foo %>% dcast(V1 + V2 ~ V3, value.var="V4") %>%
mutate(Ratio = High/Low) %>%
select(V1, V2, Ratio)
V1 V2 Ratio
1 a 1 -1.9011807
2 a 2 -0.2238274
3 a 3 -1.7143595
4 a 4 2.1606764
5 b 1 -0.9268251
6 b 2 0.1378915
7 b 3 1.3438880
8 b 4 -8.6759832
如果要在最终结果中保留select
和High
列,请删除Low
语句。
或单独使用dplyr
:
foo %>% group_by(V1, V2) %>%
summarise(Ratio = V4[V3=="High"]/V4[V3=="Low"])
或data.table
:
library(data.table)
setDT(foo)[ , list(Ratio = V4[V3=="High"]/V4[V3=="Low"]), by=list(V1, V2)]
答案 1 :(得分:0)
执行此操作的一种方法是通过V3首先split
数据帧。然后,如果它们被正确订购,那就很简单了。如果没有,则将它们合并为单个数据帧并从那里继续。例如:
# Split foo
fooSplit <- split(foo, foo$V3)
#If ordered correctly (as in the example)
fooSplit[[1]]$V4 / fooSplit[[2]]$V4
# [1] -1.9011807 -0.2238274 -1.7143595 2.1606764 -0.9268251 0.1378915 1.3438880 -8.6759832
#If not ordered correctly, merge into new dataframe
#Rename variables in prep for merge
names(fooSplit[[1]])[4] <- "High"
names(fooSplit[[2]])[4] <- "Low"
#Merge into a single dataframe, drop V3
d <- merge(fooSplit[[1]][,-3], fooSplit[[2]][,-3], by = 1:2, all = TRUE)
d$High / d$Low
# [1] -1.9011807 -0.2238274 -1.7143595 2.1606764 -0.9268251 0.1378915 1.3438880 -8.6759832
答案 2 :(得分:0)
我认为dpyr
包可以帮助你。
关注您的代码:
您可以创建“键”列,以便在“高”和“低”值之间交叉引用时使用。
foo <- mutate(foo,paste(V1,V2))
names(foo) <- c("V1","V2","V3","V4","key")
现在您可以使用过滤器的“关键”列将数据集分成两组(“高”和“低”),合并使用“关键列”和选择来加入他们以使数据集更加流畅,并保留重要的列。
foo <- select(merge(filter(foo,V3=="High"), filter(foo,V3=="Low"),
by="key"), V1.x, V2.x, V4.x, V4.y)
最后,当您在同一个表上有数据时,可以使用 mutate 创建一个新的计算列。我们再次使用选择来保持数据集尽可能简单。
foo <- select(mutate(foo,V4.x/V4.y,name="V4"),1,2,5)
所以,如果你执行:
foo <- mutate(foo,paste(V1,V2))
names(foo) <- c("V1","V2","V3","V4","key")
foo <- select(merge(filter(foo,V3=="High"), filter(foo,V3=="Low"),
by="key"), V1.x, V2.x, V4.x, V4.y)
foo <- select(mutate(foo,V4.x/V4.y,name="V4"),1,2,5)
你会得到:
# V1.x V2.x V4.x/V4.y
#1 a 1 -1.9011807
#2 a 2 -0.2238274
#3 a 3 -1.7143595
#4 a 4 2.1606764
#5 b 1 -0.9268251
#6 b 2 0.1378915
#7 b 3 1.3438880
#8 b 4 -8.6759832
可能这不是最简单的方法,但我希望它能帮到你。