组中多列的R元素到元素操作

Posted

技术标签:

【中文标题】组中多列的R元素到元素操作【英文标题】:R Element-to-Element operations on several columns in groups 【发布时间】:2020-08-17 20:26:50 【问题描述】:

我们有mtcars 数据集,并希望以多列作为输入,计算分组中不同汽车之间的函数。

更具体地说:

    按变速箱am 和齿轮gear 分组 比较同一组内的所有汽车(car1 到 car2、car1 到 car3、car2 到 car3...) 第一辆车的排量是否比第二辆车大? disp1>disp2 第一辆车的马力是否比第二辆车大? hp1>hp2

结果应该是这样的:

# Car1           Car2           result
# Mazda RX4      Mazda RX4 Wag  false
# Mazda RX4      Datsun 710     false 
# Mazda RX4 Wag  Datsun 710     true

在this question 中是按组进行的外部操作,但只使用了单个列。是否可以将其扩展到几列?如果可能,最好在结果表中包含disp1disp2 等列。

【问题讨论】:

【参考方案1】:

这有点乱,但您可以执行以下操作:

library(dplyr)
library(tidyr)

dat <- mtcars %>%
    tibble::rownames_to_column(var = "Car1") %>%
    mutate(Car2 = Car1) %>%
    group_by(am, gear) %>%
    expand(Car1, Car2) %>%
    left_join(tibble::rownames_to_column(mtcars, var = "Car1"), by = "Car1") %>%
    left_join(tibble::rownames_to_column(mtcars, var = "Car2"), by = "Car2") %>%
    ungroup() %>%
    mutate(result = disp.x > disp.y & hp.x > hp.y) %>%
    select(Car1, Car2, result)

然后我们得到预期的结果:

dat

# A tibble: 330 x 3
   Car1        Car2                result
   <chr>       <chr>               <lgl> 
 1 AMC Javelin AMC Javelin         FALSE 
 2 AMC Javelin Cadillac Fleetwood  FALSE 
 3 AMC Javelin Camaro Z28          FALSE 
 4 AMC Javelin Chrysler Imperial   FALSE 
 5 AMC Javelin Dodge Challenger    FALSE 
 6 AMC Javelin Duster 360          FALSE 
 7 AMC Javelin Hornet 4 Drive      TRUE  
 8 AMC Javelin Hornet Sportabout   FALSE 
 9 AMC Javelin Lincoln Continental FALSE 
10 AMC Javelin Merc 450SE          FALSE 
# … with 320 more rows

dat %>% filter(Car1 == "Mazda RX4")

# A tibble: 8 x 3
  Car1      Car2           result
  <chr>     <chr>          <lgl> 
1 Mazda RX4 Datsun 710     TRUE  
2 Mazda RX4 Fiat 128       TRUE  
3 Mazda RX4 Fiat X1-9      TRUE  
4 Mazda RX4 Honda Civic    TRUE  
5 Mazda RX4 Mazda RX4      FALSE 
6 Mazda RX4 Mazda RX4 Wag  FALSE 
7 Mazda RX4 Toyota Corolla TRUE  
8 Mazda RX4 Volvo 142E     TRUE

(虽然 Mazda RX4 与 Datsun 710 的比较与您所说的预期结果不同,但实际上是正确的:)

mtcars %>%
    tibble::rownames_to_column(var = "Car1") %>%
    filter(Car1 %in% c("Mazda RX4", "Datsun 710"))
        Car1  mpg cyl disp  hp drat   wt  qsec vs am gear carb
1  Mazda RX4 21.0   6  160 110 3.90 2.62 16.46  0  1    4    4
2 Datsun 710 22.8   4  108  93 3.85 2.32 18.61  1  1    4    1

【讨论】:

谢谢@duckmayr。您对expand 的使用教会了我一个新技巧。 谢谢,非常好的回答!由于我的大数据集的内存限制,我不得不采用另一种方法。【参考方案2】:

这是一个稍微更简洁(如果不那么混乱)的方法,根据要求使用outer,并显示比较hpdisp 值。它还利用reshape2::melt

library(dplyr)

f <- function(x) 
  y <- reshape2::melt(outer(x$disp, x$disp, `>`) & outer(x$hp, x$hp, `>`))
  y <- y[y[[1]] != y[[2]],]
  tibble(Car1 = rownames(x)[y[[1]]], Car2 = rownames(x)[y[[2]]],
         disp1 = x$disp[y[[1]]], disp2 = x$disp[y[[2]]],
         hp1 = x$hp[y[[1]]], hp2 = x$hp[y[[2]]], result = y[[3]])


result_list <- mtcars %>% split(paste(.$gear, .$am)) %>% lapply(f)

生成的列表对于每个齿轮/上午组合都有一个数据框。为简洁起见,我只是在这里展示了第二个:

result_list[2]
$`4 0`
# A tibble: 12 x 7
   Car1      Car2      disp1 disp2   hp1   hp2 result
   <chr>     <chr>     <dbl> <dbl> <dbl> <dbl> <lgl> 
 1 Merc 230  Merc 240D  141.  147.    95    62 FALSE 
 2 Merc 280  Merc 240D  168.  147.   123    62 TRUE  
 3 Merc 280C Merc 240D  168.  147.   123    62 TRUE  
 4 Merc 240D Merc 230   147.  141.    62    95 FALSE 
 5 Merc 280  Merc 230   168.  141.   123    95 TRUE  
 6 Merc 280C Merc 230   168.  141.   123    95 TRUE  
 7 Merc 240D Merc 280   147.  168.    62   123 FALSE 
 8 Merc 230  Merc 280   141.  168.    95   123 FALSE 
 9 Merc 280C Merc 280   168.  168.   123   123 FALSE 
10 Merc 240D Merc 280C  147.  168.    62   123 FALSE 
11 Merc 230  Merc 280C  141.  168.    95   123 FALSE 
12 Merc 280  Merc 280C  168.  168.   123   123 FALSE 

【讨论】:

谢谢。这个解决方案对我来说效果很好,没有内存问题。使用%&gt;% filter(result&gt;0),我可以只筛选出我需要的真实结果。您能否详细说明如何将函数应用于单个组合以及如何从矩阵转换为小标题? 使用reshape::melt将矩阵转换为数据框,它将nxn矩阵转换为长格式,n^2行,每个组合一个,列中矩阵的行号1,第 2 列中的列号,以及第 3 列中该组合的矩阵条目。因此,我们可以通过按第 1 列索引行名来获得第一辆车的名称,然后通过按第 2 列索引行名来获得第二辆汽车的名称。我们得到通过对 mtcars$hp 和 mtcars$hp 进行索引,hp 和 disp 的值也相同。结果只是melt 输出中最后一列的结果。 函数outer(n, m, f) 创建一个长度(m) x 长度(n) 矩阵,其中每个条目是f(m[i], n[j]) 的结果,其中i 是结果矩阵的行,@ 987654333@ 是列。在这种情况下,函数f 是运算符&lt;。由于两个outer 函数创建了两个矩阵,因此通过布尔运算符&amp; 将它们组合成一个矩阵。

以上是关于组中多列的R元素到元素操作的主要内容,如果未能解决你的问题,请参考以下文章

将列表作为单个元素插入到元组中

元组中的元素到 Bag Pig 中的元组

如何使用没有临时表的 SQL 查询为组中的每个元素添加序列号

到目前为止,按同一组中的聚合元素分组 - Pandas

求算法,将N个整数分到M个数组中,要求元素和相差最小,元素个数相差最小

Python:元组操作总结