r-第一个非零值出现的列的行名称

  • 本文关键字:第一个 非零值 r dplyr names
  • 更新时间 :
  • 英文 :


我有一堆列,它们都以前缀wtp_开头,出现在一个宽数据帧的中间(在wtp_列之前和之后有几个列(。小型示例:

df <- tribble(~id, ~complete, ~wtp_20,~wtp_40,~wtp_60,~wtp_80,~wtp_100, ~sex,
1, 1,  0,0,1,1,1,  "F",
2, 0,  0,0,0,1,1,  "F",
3, 0,  0,0,0,0,1,  "M",
4, 1,  1,1,1,1,1,  "M",
5, 1,  0,0,0,0,0,  "M",
6, 0,  0,1,1,1,1,  "F"); df

我要找的是:我需要创建一个新变量(min_wtp(,该变量在其中一个wtp_列从0切换到1的第一次时返回列的名称。换句话说,我需要一个解决方案来创建以下内容:

df_needed <- tribble(~id, ~complete, ~wtp_20,~wtp_40,~wtp_60,~wtp_80,~wtp_100, ~sex, ~min_wtp,
1, 1,  0,0,1,1,1,  "F", "wtp_60",
2, 0,  0,0,0,1,1,  "F", "wtp_80",
3, 0,  0,0,0,0,1,  "M", "wtp_100",
4, 1,  1,1,1,1,1,  "M", "wtp_20",
5, 1,  0,0,0,0,0,  "M", "NA",
6, 0,  0,1,1,1,1,  "F", "wtp_40"); df_needed

请注意以下并发症:

-有些人(如id=5(从不更改为1,而另一些人(如id=4(则一直为1
-在wtp_列之前出现了一些不相关的列,这些列中有0和1,在构造min_wtp时应忽略这些列
-列(包括wtp_列(比我上面包含的最小示例多得多。

我尝试过将whichcolnames功能与select(starts_with("wtp_"))结合使用,但都没有成功。

如果有人有dplyr解决方案,那将是首选。

我们可以使用apply为每一行获取满足您的条件的第一列的数量。然后我们使用这个数字作为索引来获得列名。

df$min_wtp = apply(df[ , grepl("wtp", names(df))], 1, function(x) {
names(x)[min(which(x > 0))]
})
df
id complete wtp_20 wtp_40 wtp_60 wtp_80 wtp_100 sex   min_wtp
<dbl>    <dbl>  <dbl>  <dbl>  <dbl>  <dbl>   <dbl> <chr> <chr>  
1     1        1      0      0      1      1       1 F     wtp_60 
2     2        0      0      0      0      1       1 F     wtp_80 
3     3        0      0      0      0      0       1 M     wtp_100
4     4        1      1      1      1      1       1 M     wtp_20 
5     5        1      0      0      0      0       0 M     NA     
6     6        0      0      1      1      1       1 F     wtp_40

如果您获得长格式的数据,会容易得多:

library(dplyr)
df %>%
tidyr::pivot_longer(cols = starts_with('wtp')) %>%
group_by(id) %>%
summarise(min_wtp = name[which(value == 1 & 
lag(value, default = 0) == 0)[1]]) %>%
left_join(df, by = 'id')
# A tibble: 6 x 9
#     id min_wtp complete wtp_20 wtp_40 wtp_60 wtp_80 wtp_100 sex  
#  <dbl> <chr>      <dbl>  <dbl>  <dbl>  <dbl>  <dbl>   <dbl> <chr>
#1     1 wtp_60         1      0      0      1      1       1 F    
#2     2 wtp_80         0      0      0      0      1       1 F    
#3     3 wtp_100        0      0      0      0      0       1 M    
#4     4 wtp_20         1      1      1      1      1       1 M    
#5     5 NA             1      0      0      0      0       0 M    
#6     6 wtp_40         0      0      1      1      1       1 F   

在不重塑数据的情况下,您可以将rowwisec_across:一起使用

apply_fun <- function(x) {
which(x == 1 & lag(x, default = 0) == 0)[1]
}
cols <- grep('^wtp', names(df), value = TRUE)
df %>%
rowwise() %>%
mutate(min_wtp = cols[apply_fun(c_across(cols))])

如果它从不从1倒退到0,那么你可以用一些基本的和很快找到变化点:

sw  <- startsWith(names(df), "wtp_")
names(df[sw])[sum(sw) - rowSums(df[sw]) + 1]
#[1] "wtp_60"  "wtp_80"  "wtp_100" "wtp_20"  NA        "wtp_40"

最新更新