按组用第一个观察值替换所有值

D. *_*ler 3 r dataframe dplyr

对于由“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)

然而,这似乎并没有做到。有人可以帮忙吗?

r2e*_*ans 5

如果您想要 @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::firstdata.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)


Hen*_*rik 5

使用的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)


akr*_*run 3

我们可以使用firstonacrossmutate

library(dplyr)
df %>%
    arrange(id, Visit) %>% 
    group_by(id) %>% 
    mutate(across(c(x, y), first)) %>%
    ungroup
Run Code Online (Sandbox Code Playgroud)