R 元素到元素的操作在组中的几列

R Element-to-Element operations on several columns in groups

我们有 mtcars 数据集,想要计算一组不同汽车之间的函数,将几列作为输入。

更具体地说:

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

结果应如下所示:

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

中是按组进行外层操作,但只用到了单列。是否可以将其扩展到多个列?如果可能的话,最好在结果 table.

中包含 disp1disp2 等列

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

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

(虽然马自达 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

根据要求,这里有一个使用 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