基于重复序列将数据框行分组

4

我有一个下面的示例数据框。 我试图取每个3行序列并将第一个除以第三个(或换句话说,对于每个id,将类“a”除以类“c”)。 如何最直接地做到这一点? 提前感谢。

 id class value
 0  a   241
 0  b   109
 0  c   350
40  a   239
40  b   160
40  c   399
53  a   158
53  b   97
53  c   255
54  a   239
54  b   78
54  c   317
2个回答

2
您可以使用byid分组,然后使用valueclass进行子集操作:
by(data = data, INDICES = data$id, 
   FUN = function(ds) ds[ds$class == "a", "value"] / 
                      ds[ds$class == "c", "value"])

这将为每个 id 生成一个单一的值。输出结果:
data$id: 0
[1] 0.6885714
----------------------------------------------------------------------------------------- 
data$id: 40
[1] 0.5989975
------------------------------------------------------------------------------------------ 
data$id: 53
[1] 0.6196078
------------------------------------------------------------------------------------------ 
data$id: 54
[1] 0.7539432

可以,谢谢。但是我想要把输出作为数据框的另一列插入进去。你知道怎么将输出转换为数据框的列吗? - SilvanD
没事了 - 我想通了。dat<-do.call(rbind, dat) #转换为数据框 dat<-rep(dat, each=3) 然后我把它塞回原始数据框中。我相信有更优雅的解决方案,但这个方法很管用。感谢您的好建议。 - SilvanD
@SilvanD 这就是我的前两个解决方案优雅的做法(并且我也首先发布了它)。接受另一个不符合您要求格式的解决方案对我来说没有意义。 - akrun
@SilvanD 关于这个解决方案和使用 rep 来填充行以适用于此示例,但请考虑数据是否有序,即 df1$id[1:3] <- 59。然后输出列表将会是不同的顺序,那么您可能需要匹配列表名称,然后执行 rep - akrun

1
我们可以尝试使用来自基本R的split / unsplit。通过'id'列将数据集拆分为'list'输出,使用lapply循环遍历列表,通过添加一个新列('value1')来转换data.frame列表元素,该列基于除以与'class'(a和c)对应的'value',然后通过'id'列unsplit。
 unsplit(lapply(split(df1, df1$id), function(x) 
      transform(x, value1= value[class=='a']/value[class=='c'])), df1$id)
 #   id class value    value1
 #1   0     a   241 0.6885714
 #2   0     b   109 0.6885714
 #3   0     c   350 0.6885714
 #4  40     a   239 0.5989975
 #5  40     b   160 0.5989975
 #6  40     c   399 0.5989975
 #7  53     a   158 0.6196078
 #8  53     b    97 0.6196078
 #9  53     c   255 0.6196078
 #10 54     a   239 0.7539432
 #11 54     b    78 0.7539432
 #12 54     c   317 0.7539432

或者使用 dplyr 中的 mutate 在按 'id' 列分组后创建新列。

library(dplyr)
df1 %>% 
     group_by(id) %>% 
      mutate(value1= value[class=='a']/value[class=='c'])
#    id class value    value1
#1   0     a   241 0.6885714
#2   0     b   109 0.6885714
#3   0     c   350 0.6885714
#4  40     a   239 0.5989975
#5  40     b   160 0.5989975
#6  40     c   399 0.5989975
#7  53     a   158 0.6196078
#8  53     b    97 0.6196078
#9  53     c   255 0.6196078
#10 54     a   239 0.7539432
#11 54     b    78 0.7539432
#12 54     c   317 0.7539432

如果是基于位置的,例如第一个和最后一个,您可以通过更改上述代码中的最后一行来进行更改。

      mutate(value1=first(value)/last(value))

或者一种紧凑的方法是使用data.table。 使用:=运算符在创建'value1'列时非常快速。 将'data.frame'更改为'data.table'(setDT(df1)),按'id'分组创建'value1'列。 在这里,我选择了'value'的第一个(1L)和最后一个观察值(.N),假设'a'和'c'已排序。 如果未排序,则像以前一样使用value[class =='a'] / value[class =='c']

library(data.table)
setDT(df1)[, value1:=value[1L]/value[.N] , id]
#   id class value    value1
#1:  0     a   241 0.6885714
#2:  0     b   109 0.6885714
#3:  0     c   350 0.6885714
#4: 40     a   239 0.5989975
#5: 40     b   160 0.5989975
#6: 40     c   399 0.5989975
#7: 53     a   158 0.6196078
#8: 53     b    97 0.6196078
#9: 53     c   255 0.6196078
#10:54     a   239 0.7539432
#11:54     b    78 0.7539432
#12:54     c   317 0.7539432

或者使用 base R 的另一种方法。虽然在示例数据集上有效,但在数据未排序的情况下可能无法正常工作。

df1$value1 <- (df1$value[df1$class=='a']/
        df1$value[df1$class=='c'])[as.numeric(factor(df1$id))]

更新

如果您需要每个id的单个值,请在dplyr中将mutate替换为summarise

 df1 %>%
    group_by(id) %>% 
    summarise(value1= value[class=='a']/value[class=='c'])
 #   id    value1
 #1  0 0.6885714
 #2 40 0.5989975
 #3 53 0.6196078
 #4 54 0.7539432

或者在 data.table 中删除赋值符号 (:=)。

setDT(df1)[, list(value1=value[class=='a']/value[class=='c']), id]
 #    id    value1
 #1:  0 0.6885714
 #2: 40 0.5989975
 #3: 53 0.6196078
 #4: 54 0.7539432

数据

df1 <- structure(list(id = c(0L, 0L, 0L, 40L, 40L, 40L, 53L, 53L, 53L, 
54L, 54L, 54L), class = c("a", "b", "c", "a", "b", "c", "a", 
"b", "c", "a", "b", "c"), value = c(241L, 109L, 350L, 239L, 160L, 
399L, 158L, 97L, 255L, 239L, 78L, 317L)), .Names = c("id", "class", 
"value"), class = "data.frame", row.names = c(NA, -12L))

感谢您详尽的答案,akrun。我对dplyr不是很熟悉,但似乎值得更加了解!然而,我在您的答案中并没有取得太大的成功。它一直返回:错误:大小不兼容(%d),期望 %d(组大小)或 1。 - SilvanD
@SIlvanD 我已经更新了使用的数据集。我使用 dplyr_0.4.1.9000 没有遇到任何错误。 - akrun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接