样本数据:
df <- data.frame(bucket = c("A", "B", "C", "D"),
apples = c("<4", "U", "22", "9"),
oranges = c("U", "<4", "15", "7"),
bananas = c("8", "6", "16", "<4"),
pears = c("U", "7", "<4", "10"))
我期望的输出:
bucket apples oranges bananas pears
1 A <4 U 8 U
2 B U <4 6 7
3 C 22 U 16 <4
4 D 9 U <4 10
这个想法是我试图替换最低的带字母"u"的数值在每个行中。还请注意,我将"桶列"视为具有非唯一行。
然而,也有一些例外;
- 如果该行有多个"<4"实例,则不要更改该行中的任何内容。
- 如果该行已经有至少一个"U"实例,则不要更改该行中的任何内容。
我试过了:
for(i in 1:nrow(df)){
if(sum(df[i,] == "U") > 0 || sum(df[i,] == "<4") > 1){
next
} else {
df <- df %>%
rowwise() %>%
mutate(across(everything(),
~replace(.x, which.min(.x), "U")))
}
}
作为一个主要的tidyverse用户,我似乎无法理解如何正确使用rowwise
与mutate
和across
。
一个整洁的宇宙解决方案是很棒的,但也很乐意采用其他解决方案。
一种方法是转换为长格式,再转换为宽格式,即
library(dplyr)
library(tidyr)
df %>%
pivot_longer(-1) %>%
group_by(bucket) %>%
mutate(value1 = value,
U_Exists = any(value == 'U'),
value = as.numeric(value),
value = replace(value, which.min(value), 'U'),
value_final = ifelse(!U_Exists, value, value1),
value_final = replace(value_final, is.na(value_final), value1[is.na(value_final)])) %>%
select(-c(value, value1, U_Exists)) %>%
pivot_wider(names_from = name, values_from = value_final)
# A tibble: 4 x 5
# Groups: bucket [4]
bucket apples oranges bananas pears
<chr> <chr> <chr> <chr> <chr>
1 A <4 U 8 U
2 B U <4 6 7
3 C 22 U 16 <4
4 D 9 U <4 10
注意:(良性)警告是由于NAs转换为数值型。