如何基于其他列在单个列中的值之间应用除法运算?

时间:2015-06-12 22:09:16

标签: r dataframe

我有一个相当大的数据框,有一个数字列和一堆因子。其中一个因素只有两个值。我想生成一个新的,较小的数据框,将数值变量除以同一列中的另一个值。

示例数据:

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可能已被删除)

我假设我不得不以某种方式重构我的数据框,但我不知道从哪里开始。提前谢谢。

3 个答案:

答案 0 :(得分:1)

以下是使用dplyrreshape2的选项:

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

如果要在最终结果中保留selectHigh列,请删除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包可以帮助你。 关注您的代码:

  1. 您可以创建“键”列,以便在“高”和“低”值之间交叉引用时使用。

    foo <- mutate(foo,paste(V1,V2))  
    names(foo) <- c("V1","V2","V3","V4","key")
    
  2. 现在您可以使用过滤器的“关键”列将数据集分成两组(“高”和“低”),合并使用“关键列”和选择来加入他们以使数据集更加流畅,并保留重要的列。

    foo <- select(merge(filter(foo,V3=="High"), filter(foo,V3=="Low"), 
                                             by="key"), V1.x, V2.x, V4.x, V4.y)
    
  3. 最后,当您在同一个表上有数据时,可以使用 mutate 创建一个新的计算列。我们再次使用选择来保持数据集尽可能简单。

    foo <- select(mutate(foo,V4.x/V4.y,name="V4"),1,2,5)
    
  4. 所以,如果你执行:

    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
    

    可能这不是最简单的方法,但我希望它能帮到你。