Как отфильтровать сгруппированный фрейм данных с помощью условного оператора, используя dplyr? - PullRequest
1 голос
/ 29 марта 2020

Я хочу отфильтровать фрейм данных, используя dplyr, используя условный. Условие, которое я хочу проверить, состоит в том, имеет ли комбинация страна-год две версии.

df <- data.frame(country = c("country1", "country2", "country1", "country2", "country3"), year = rep(2011,5), version = c("versionA", "versionA", "versionB", "versionB", "versionB"))

Вот то, что я попробовал, посмотрев здесь :

df %>%
     group_by(country, year) %>%
     {if unique(version)==1 . else filter(version == "versionA")}

Я надеюсь получить кадр данных, который выглядит следующим образом:

country     year     version

country1    2011     versionA
country2    2011     versionA
country3    2011     versionB

Ответы [ 3 ]

1 голос
/ 29 марта 2020

Для подсчета количества уникальных значений мы можем использовать n_distinct и отфильтровать строки на основе этого.

library(dplyr)

df %>%
  group_by(country, year) %>%
  filter(if(n_distinct(version) == 2) version == 'versionA' else TRUE)


#  country   year version 
#  <fct>    <dbl> <fct>   
#1 country1  2011 versionA
#2 country2  2011 versionA
#3 country3  2011 versionB
1 голос
/ 29 марта 2020

Base R, один вкладыш, спасибо (@akrun):

df[!(duplicated(df[1:2])),]

Base R, один вкладыш:

df[!(duplicated(df$country, df$year)),]

Tidyverse решение:

library(tidyverse)
df %>%
  filter(!(duplicated(country, year)))

Более универсальное c базовое решение R:

# Create a counter of versions for each year and country: 

df$tmp <- with(lapply(df, function(x){if(is.factor(x)){as.character(x)}else{x}}),
               ave(version, paste0(country, year), FUN = seq.int))

# Subset the dataframe to hold only the first record for each year/country: 

df[which(df$tmp == 1), ]

Более универсальное c решение в обратном направлении:

df %>%
  arrange(version) %>% 
  filter(!(duplicated(country, year)))
1 голос
/ 29 марта 2020

После группировки по 'стране', 'году', filter, если число отдельных элементов больше 1, возвращает 'versionA' или же возвращает первый элемент

library(dplyr)
df %>%
  group_by(country, year)  %>% 
  filter((n_distinct(version)  > 1 & version == 'versionA')|row_number() == 1)
# A tibble: 3 x 3
# Groups:   country, year [3]
#  country   year version 
#  <fct>    <dbl> <fct>   
#1 country1  2011 versionA
#2 country2  2011 versionA
#3 country3  2011 versionB

Или это может быть добавлено в if/else

df %>%
    group_by(country, year) %>%
    filter(if(n_distinct(version) > 1) version == 'versionA'
       else row_number() ==1)
# A tibble: 3 x 3
# Groups:   country, year [3]
#  country   year version 
#  <fct>    <dbl> <fct>   
#1 country1  2011 versionA
#2 country2  2011 versionA
#3 country3  2011 versionB

Или другой вариант arrange

df %>% 
    arrange(country, year, version != 'versionA') %>% 
    group_by(country, year) %>% 
    slice(1)

Или с summarize

df %>%
    group_by(country, year) %>%
    summarise(version = if(n_distinct(version) > 1) 'versionA' else first(version))

Или используя data.table

library(data.table)
setDT(df)[, .SD[if(n_distinct(version) > 1) version == 'versionA' 
          else 1], .(country, year)]
...