【问题标题】:How to find intersection of values that meet multiple conditions in R? [closed]如何在R中找到满足多个条件的值的交集? [关闭]
【发布时间】:2021-12-03 21:59:25
【问题描述】:

假设我有以下数据框:

df <- data.frame(year=c(2010,2011,2012,2010,2011,2010,2011,2012), company = c("a","a","a","b","b","c","c","c"))

  year company
1 2010       a
2 2011       a
3 2012       a
4 2010       b
5 2011       b
6 2010       c
7 2011       c
8 2012       c

我想查找所有三年中都存在的公司。一种麻烦的方法是:

library(dplyr)

companies_2010 <- df %>% filter(year==2010) %>% select(company)
companies_2011 <- df %>% filter(year==2011) %>% select(company)
companies_2012 <- df %>% filter(year==2012) %>% select(company)

companies <- intersect(companies_2010, companies_2011) %>% intersect(., companies_2012)

  company
1       a
2       c

有没有更优雅的方法来做到这一点?

【问题讨论】:

    标签: r dataframe


    【解决方案1】:

    由于年份不同且在所需的集合中,我们只需计算每家公司有多少。 (如果这不是真的,一般来说,然后将下面的解决方案应用于df2 &lt;- unique(merge(df, data.frame(year = 2010:2012))) 代替 df。此外,如果我们不知道值 3 并且我们希望它等于数据中唯一年份的数量,那么我们可以使用length(unique(df$year)) 计算它。

    现在,使用这个想法有几个选择。我们可以使用 table 来获取它们的频率,然后保留频率为 3 的那些,或者在最后一种情况下,我们可以使用 dplyr 的计数,然后过滤以获取计数为 3 的那些。

    tab <- table(df$company)
    names(tab)[tab == 3]
    ## [1] "a" "c"
    
    names(Filter(function(x) x == 3, table(df$company)))
    ## [1] "a" "c"
    
    library(dplyr)   
    df %>%
      count(company) %>%
      filter(n == 3) %>%
      select(company)
    ##   company
    ## 1       a
    ## 2       c
    

    利用问题按年拆分公司的相交思想,然后用Reduce反复申请相交:

     with(df, Reduce(intersect, split(company, year)))
     ## [1] "a" "c"
    

    我们可以使用这样的表格来可视化这一点。任何没有零值的列都对应于拥有所有年份的公司。

    table(df)
    ##       company
    ## year   a b c
    ##   2010 1 1 1
    ##   2011 1 1 1
    ##   2012 1 0 1
    

    或者是一个有绿色没有红色的热图。任何完全为绿色的列都有所有年份。

    heatmap(table(df), Rowv = NA, Colv = NA, col = 2:3, scale = "none")
    

    【讨论】:

      【解决方案2】:

      这是带有aveunique 的基本R 解决方案。

      n <- with(df, ave(year, company, FUN = length))
      unique(df$company[n == 3])
      #[1] "a" "c"
      

      【讨论】:

        【解决方案3】:

        既然你已经收到了一些很好的答案,我想一个非常不同的方法加上一点想象力也可以。

        我将您的问题设置为一个二分图,其中我们有 2 组不同的节点,其中一个是公司名称,另一个是年份,而公司之间以及年份之间没有联系。

        library(igraph)
        
        # Creating a graph object but first I alternate the columns of your data set
        df[, c(2, 1)] |>
          graph_from_data_frame() -> g
        
        # Then we create a type object to distinguish between 2 sets of nodes, Type FALSE
        # refers to company name and type TRUE refers to years
        V(g)$type <- bipartite.mapping(g)$type
        
        # Then we extract those nodes whose degree are equal to 3 while they are of type FALSE
        V(g)[degree(g, V(g)) == length(unique(df$year)) & V(g)$type == FALSE]
        + 2/6 vertices, named, from c172916:
        [1] a c
        

        如果您想查看图表的外观:

        plot(g,
             vertex.color = ifelse(V(g)$type, "lightblue", "salmon"),
             vertex.shape = ifelse(V(g)$type, "circle", "square"),
             vertex.size = 25,
             edge.color = "grey",
             layout = layout.bipartite)
        

        【讨论】:

          【解决方案4】:

          一般不能用于计算任意交叉点,但是 (¿ 我认为 ?) 可以按照您在上面指定的方式工作:

          (df 
             %>% group_by(company)
             %>% filter(all(2010:2012 %in% year))
             %>% select(company)
             %>% distinct()
          )
          

          【讨论】:

            【解决方案5】:

            解释给出的答案,这通常会起作用:

            df %>%
              mutate(rn = list(seq(min(year), max(year))))%>%
              group_by(company) %>%
              summarise(rn = all(unlist(rn) %in% year)) %>%
              filter(rn) %>%
              select(company)
            
            # A tibble: 2 x 1
              company
              <chr>  
            1 a      
            2 c  
            

            【讨论】:

              【解决方案6】:

              只是嵌套和减少:

              df <- data.frame(year=c(2010,2011,2012,2010,2011,2010,2011,2012), company = c("a","a","a","b","b","c","c","c"))
              df %>% 
                  tidyr::nest(data = -year) %>% 
                  magrittr::use_series(data) %>% 
                  purrr::reduce(dplyr::intersect)
              # A tibble: 2 x 1
                company
                <chr>  
              1 a      
              2 c 
              

              或拆分映射减少:

              split.data.frame(df, df$year) %>% 
                  purrr::map(magrittr::use_series, company) %>% 
                  purrr::reduce(dplyr::intersect)
              [1] "a" "c"
              

              【讨论】:

                【解决方案7】:

                另一个igraph 解决方案

                > g <- graph_from_data_frame(df)
                
                > names(which(degree(g, V(g)[names(V(g)) %in% df$company]) == length(unique(df$year))))
                [1] "a" "c"
                

                【讨论】:

                  猜你喜欢
                  • 2018-07-06
                  • 2016-03-17
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-01-22
                  • 2013-10-19
                  • 1970-01-01
                  相关资源
                  最近更新 更多