我有一个数据框(df),我想添加一个额外的列result,使用dplyr将取值1 if z == "gone"和where x是组的最大值y.
y x z
1 a 3 gone
2 a 5 gone
3 a 8 gone
4 a 9 gone
5 a 10 gone
6 b 1
7 b 2
8 b 4
9 b 6
10 b 7
Run Code Online (Sandbox Code Playgroud)
如果我只是为每个组选择最大值,它将是:
df %>%
group_by(y) %>%
slice(which.max(x))
Run Code Online (Sandbox Code Playgroud)
将返回:
y x z
1 a 10 gone
2 b 7
Run Code Online (Sandbox Code Playgroud)
这不是我想要的.我需要利用x每个组的最大值,y同时检查是否z == "gone",如果TRUE1 则为0.否则为0.这样看起来像:
y x z result
1 a 3 gone 0
2 a 5 gone 0
3 a 8 gone 0
4 a 9 gone 0
5 a 10 gone 1
6 b 1 0
7 b 2 0
8 b 4 0
9 b 6 0
10 b 7 0
Run Code Online (Sandbox Code Playgroud)
我假设我会在其中使用条件语句,mutate()但我似乎无法找到一个例子.请指教.
我们可以这样做data.table.我们将'data.frame'转换为'data.table'(setDT(df)),按'y'分组,我们创建'x'的最大值的逻辑条件和'z'中的'gone'元素,将其强制转换为'整数'(as.integer)和赋值(:=)输出到新列('结果').
library(data.table)
setDT(df)[, result := as.integer(x==max(x) & z=='gone') , by = y]
df
# y x z result
# 1: a 3 gone 0
# 2: a 5 gone 0
# 3: a 8 gone 0
# 4: a 9 gone 0
# 5: a 10 gone 1
# 6: b 1 0
# 7: b 2 0
# 8: b 4 0
# 9: b 6 0
#10: b 7 0
Run Code Online (Sandbox Code Playgroud)
或者我们可以使用ave从base R
df$result <- with(df, +(ave(x, y, FUN=max)==x & z=='gone' ))
Run Code Online (Sandbox Code Playgroud)
随dplyr你可以使用:
df %>% group_by(y) %>% mutate(result = +(x == max(x) & z == 'gone'))
Run Code Online (Sandbox Code Playgroud)
该+(..)表示法是简写as.integer到逻辑输出强制为1和0.有些人不喜欢它,所以这是一个较短的代码与可读性的问题.效率增益可以在这种情况下进行辩论.
也体会到了什么data.table和dplyr做了与R数据操纵,让我们做同样的事情在老式的"裂应用于-相结合"的方式:
#split data.frame by group
split.df <- split(df, df$y)
#apply required function to each group
lst <- lapply(split.df, function(dfx) {
dfx$result <- +(dfx$x == max(dfx$x) & dfx$z == "gone")
dfx})
#combine result in new data.frame
newdf <- do.call(rbind, lst)
Run Code Online (Sandbox Code Playgroud)