出现第一个非零值的列的按行名称
Rowwise name of column where first non-zero value appears
我有一堆列都以前缀 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
),returns 第一次 列的名称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_
列)比我上面包含的最小示例多得多。
我试过将 which
和 colnames
函数与 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
无需重塑数据,您可以将 rowwise
与 c_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"
我有一堆列都以前缀 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
),returns 第一次 列的名称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_
列)比我上面包含的最小示例多得多。
我试过将 which
和 colnames
函数与 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
无需重塑数据,您可以将 rowwise
与 c_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"