显示包含一些已排序的分组数据的行的数据框。需要引入一个新列,其值取决于某些列的值。
如果第一个值为零,那么如果没有这样的值,则组的所有值都将获得第一个非零值或NA
。否则,如果第一个值不为零,则分配固定值,例如, -1
。
示例输入数据框:
df <- data.frame(
name = c("A", "A", "A", "A", "B", "B", "C", "C"),
value = c(0, 0, 6, 3, 0, 0 , 7, 0))
创建 calc 列的示例输出数据框:
df <- data.frame(
name = c("A", "A", "A", "A", "B", "B", "C", "C"),
value = c(0, 0, 6, 3, 0, 0 , 7, 0),
calc = c(6, 6, 6, 6, NA, NA, -1, -1))
提前谢谢。
P.S。:基础R是优选的
答案 0 :(得分:3)
以下是基础R的一种方法:
df$calc <- unlist(tapply(df$value, df$name, function(x) rep(if(x[1]==0) x[x!=0][1] else -1, length(x))))
......还有更好的方法:
df$calc <- ave(df$value, df$name, FUN = function(x) if(x[1]==0) x[x!=0][1] else -1)
两部分可以理解:
首先,编写一个符合您所需条件的函数。
doit <- function(x) if(x[1]==0) x[x!=0][1] else -1
其次,在ave
中使用它:
ave(df$value, df$name, FUN=doit)
|编辑|
如果我想分配给&#34; calc&#34;如何修改功能?列来自另一列的值,例如&#34; value2&#34;,对应于第一个非零&#34;值&#34;?
此处ave
不再为您提供帮助,您需要split
数据框并重新加入。
df$value2 <- 101:108
do.call(rbind, lapply(split(df, df$name), function(x) {
x $ calc <- with(x, ifelse(value[1]==0, value[value!=0][1], value2[value2!=0][1]))
x
}))
请注意function(x)
中的第二行...这是返回整个x
而不仅仅是$calc
组件。逻辑顺序是:split - &gt; lapply - &gt; do.call但是由于括号的工作方式,它看起来相反。可以使用magrittr中的管道重写这一点,以便保留逻辑顺序(管道LHS %>% RHS
将LHS作为第一个参数转发给RHS,因此需要do.call
的技巧,我们希望它是第二个论点。)。
library(magrittr)
split(df, df$name) %>%
lapply(function(x) {
x $ calc <- with(x, ifelse(value[1]==0, value[value!=0][1], value2[value2!=0][1]))
x
}) %>% {do.call(rbind, .)}
答案 1 :(得分:2)
以下是data.table
library(data.table)
setDT(df)[, calc := if(!value[1]) value[value != 0][1] else -1, name]
df
# name value calc
#1: A 0 6
#2: A 0 6
#3: A 6 6
#4: A 3 6
#5: B 0 NA
#6: B 0 NA
#7: C 7 -1
#8: C 0 -1
答案 2 :(得分:1)
您可以将group_by
和case_when
与dplyr
:
library(tidyverse)
df %>%
group_by(name) %>%
mutate(calc = case_when(
first(value) != 0 ~ -1.,
max(value) == 0 ~ NA_real_,
TRUE ~ value[value != 0][1]))
输出:
# A tibble: 8 x 3
# Groups: name [3]
name value calc
<fct> <dbl> <dbl>
1 A 0. 6.
2 A 0. 6.
3 A 6. 6.
4 A 3. 6.
5 B 0. NA
6 B 0. NA
7 C 7. -1.
8 C 0. -1.
答案 3 :(得分:0)
我同意@ andrew_reece的回答。
你甚至可以跳过line max(value) == 0 ~ NA_real_
,因为calc
无论如何都会被设置为NA,所以“写”可能会更短:
df %>%
group_by(name) %>%
mutate(calc = ifelse(first(value) == 0, value[value != 0][1], -1))