对于由“id”定义的每个组,我想选择列“x”和“y”的第一行中的值,并将所有后续值替换为该第一个值。
一些数据:
id Visit x y
1 1 0 1
1 2 1 2
1 3 2 8
2 9 1 11
2 10 12 14
Run Code Online (Sandbox Code Playgroud)
我想要:
id Visit x y
1 1 0 1
1 2 0 1 # <- x & y replaced with first values of 'id' 1
1 3 0 1 #
2 9 1 11
2 10 1 11 # <- x & y replaced with first values of 'id' 2
Run Code Online (Sandbox Code Playgroud)
我试过这个:
df1 <- df %>%
arrange(id, Visit) %>%
group_by(id) %>%
fill(x, y,
.direction = 'down',)
Run Code Online (Sandbox Code Playgroud)
然而,这似乎并没有做到。有人可以帮忙吗?
如果您想要 @akrun 很棒的答案的基本 R 版本:
df[c("x","y")] <- lapply(df[c("x","y")], function(z) ave(z, df$id, FUN = function(y) y[1]))
df
# id Visit x y
# 1 1 1 0 1
# 2 1 2 0 1
# 3 1 3 0 1
# 4 2 9 1 11
# 5 2 10 1 11
Run Code Online (Sandbox Code Playgroud)
(我故意避免使用dplyr::first或data.table::first,因为这会破坏使用此基本 R 版本的意义。)
或者 data.table 变体:
library(data.table)
setDT(df)
df[, c("x","y") := lapply(.SD[,c("x","y")], first), by = .(id)]
Run Code Online (Sandbox Code Playgroud)
正如 @Henrik 刚刚提到的,在这里使用(好多了!)更好.SDcols:
df[, c("x","y") := lapply(.SD, first), by = .(id), .SDcols = c("x","y")]
Run Code Online (Sandbox Code Playgroud)
使用的base替代方法duplicated:
df[, c("x", "y")] = df[(i = !duplicated(df$id)), c("x", "y")][cumsum(i), ]
# id Visit x y
# 1 1 1 0 1
# 2 1 2 0 1
# 3 1 3 0 1
# 4 2 9 1 11
# 5 2 10 1 11
Run Code Online (Sandbox Code Playgroud)
使用data.table滚动连接“填充”每个组中的第一个值(在较大数据上快速):
library(data.table)
setDT(df)
df[ , c("x", "y") := df[!duplicated(id)][.SD, on = .(id, Visit), .(x, y), roll = Inf]]
df
# id Visit x y
# 1: 1 1 0 1
# 2: 1 2 0 1
# 3: 1 3 0 1
# 4: 2 9 1 11
# 5: 2 10 1 11
Run Code Online (Sandbox Code Playgroud)
我们可以使用firstonacrossmutate
library(dplyr)
df %>%
arrange(id, Visit) %>%
group_by(id) %>%
mutate(across(c(x, y), first)) %>%
ungroup
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
323 次 |
| 最近记录: |