我有一个下面的示例数据框。 我试图取每个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
by
按id分组,然后使用value和class进行子集操作:by(data = data, INDICES = data$id,
FUN = function(ds) ds[ds$class == "a", "value"] /
ds[ds$class == "c", "value"])
data$id: 0
[1] 0.6885714
-----------------------------------------------------------------------------------------
data$id: 40
[1] 0.5989975
------------------------------------------------------------------------------------------
data$id: 53
[1] 0.6196078
------------------------------------------------------------------------------------------
data$id: 54
[1] 0.7539432
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))
dplyr_0.4.1.9000
没有遇到任何错误。 - akrun
rep
来填充行以适用于此示例,但请考虑数据是否有序,即df1$id[1:3] <- 59
。然后输出列表将会是不同的顺序,那么您可能需要匹配列表名称,然后执行rep
。 - akrun