В R пытаюсь реализовать следующую логику фильтрации по группам в большом наборе данных:
Внутри каждой группы:
Если более одного L, сохраните строку с наименьшим значением L.
Если N больше одного, сохраните строку с наибольшим значением N.
Если и L, и N, удалите любую строку, где N больше, чем L.
Если и L, и N, оставьте строку с самым высоким значением N ниже самого низкого значения L (в дополнение к самому низкому значению L).
Сохраните все значения B.
Пример данных:
dat <- data.frame(group=c("AB","AB","AB","AB","BC","BC","B","B","AD","AD","AD","G"),
type=c("B","L","N","N","N","L","N","N","B","L","L","L"),
value=c(2,4,3,2,5,3,8,9,4,3,9,7))
желаемый результат:
desired_output <- data.frame(group=c("AB","AB","AB","BC","B","AD","AD","G"),
type=c("B","L","N","L","N","B","L","L"),
value=c(2,4,3,3,9,4,3,7))
Ищем решение dplyr/tidyr. Я пробовал фильтровать логику после Pivot_wider или Case_When внутри фильтра, но мне это не удалось. Я ожидал, что это будет просто, но применение логики к столбцам поставило меня в тупик.
Это примерно то, о чем я думал, но не дает желаемого результата (например, L принимает min для всех типов внутри группы, а не только внутри L):
df <- dat %>%
group_by(group) %>%
filter(type= = "B"|type= = "L" & value==min(value)|type= = "N" & value==max(value))
значение, извините, это было неясно!
Что, если есть и L, и N, но все значения N превышают наименьшее значение L?
Спасибо, я добавил уточнения в пост. Если значение N выше L, я бы хотел удалить строку(и) N.





Вы можете попробовать:
### Packages
library(dplyr)
library(tidyr)
### Data
dat <- data.frame(group=c("AB","AB","AB","AB","BC","BC","B","B","AD","AD","AD","G"),
type=c("B","L","N","N","N","L","N","N","B","L","L","L"),
value=c(2,4,3,2,5,3,8,9,4,3,9,7))
### We add the number of L and N for each group
dat2=dat %>%
group_by(group) %>%
mutate(nb_L = sum (type == "L"),
nb_N = sum (type == "N")) %>%
ungroup()
### We create 3 dataframes that respect your conditions
a=dat2 %>% group_by(group) %>% filter(nb_L>1&type= = "L") %>% slice_min(value,n = 1) %>% ungroup()
b=dat2 %>% group_by(group) %>% filter(nb_N>1&type= = "N") %>% slice_max(value,n=1) %>% ungroup()
c=dat2 %>% group_by(group) %>% filter(type= = "B"|(nb_L<=1&type= = "L")|(nb_N<=1&type= = "N")) %>% ungroup()
### We stack the dataframes
dat2=bind_rows(a,b,c) %>% ungroup()
### We add the value of L and N for each group
### We remove the rows regarding the rest of your criterias
dat2=dat2 %>%
group_by(group) %>%
mutate(val_L = ifelse(type == "L", value, NA_real_),
val_N = ifelse(type == "N", value, NA_real_)) %>%
fill(c(val_L,val_N), .direction = "downup") %>%
mutate(across(c(val_L,val_N),~replace_na(.x,0)),
keep=case_when(nb_L>0&type= = "N"&val_N>val_L~"remove",.default = "keep")) %>%
filter(keep= = "keep") %>%
select(group,type,value) %>%
arrange(group,type) %>%
ungroup()
Выход :
# A tibble: 8 × 3
group type value
<chr> <chr> <dbl>
1 AB B 2
2 AB L 4
3 AB N 3
4 AD B 4
5 AD L 3
6 B N 9
7 BC L 3
8 G L 7
это здорово, спасибо! Я не подумал об этом первом шаге.
Вот возможное решение с помощью подхода pivot_wider --> map_ --> pivot_longer.
(данные об игрушке в конце)
library(tidyverse) # purrr, tidyr
new_df <- my_df %>%
pivot_wider(id_cols = group, names_from = type, values_from = value, values_fn = list) %>%
mutate(
L = map(L, \(x) if (!is.null(x)) min(x) else NA_real_),
N = map(N, \(x) if (!is.null(x)) max(x) else NA_real_),
N = map2(N, L, \(x, y) if (x > y & !is.na(x) & !is.na(y)) NA_real_ else x)) %>%
pivot_longer(-group, names_to = "type", values_drop_na = TRUE) %>%
unnest_longer(value) %>%
filter(!is.na(value))
Выход:
> new_df
# A tibble: 8 × 3
group type value
<chr> <chr> <dbl>
1 AB B 2
2 AB L 4
3 AB N 3
4 BC L 3
5 B N 9
6 AD B 4
7 AD L 3
8 G L 7
Вот и все, надеюсь, это поможет!
Данные игрушки:
# Toy data
my_df <- tibble::tribble(
~group, ~type, ~value,
"AB", "B", 2, #
"AB", "L", 4, #
"AB", "N", 3, #
"AB", "N", 2,
"BC", "N", 5,
"BC", "L", 3, #
"B", "N", 8,
"B", "N", 9, #
"AD", "B", 4, #
"AD", "L", 3, #
"AD", "L", 9,
"G", "L", 7) #
Created on 2024-05-20 with reprex v2.1.0
самый низкий/самый высокий/ниже по значению или по порядку строк?