组中多列的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 中是按组进行的外部操作,但只使用了单个列。是否可以将其扩展到几列?如果可能,最好在结果表中包含disp1
、disp2
等列。
【问题讨论】:
【参考方案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
,并显示比较hp
和disp
值。它还利用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
【讨论】:
谢谢。这个解决方案对我来说效果很好,没有内存问题。使用%>% filter(result>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
是运算符<
。由于两个outer
函数创建了两个矩阵,因此通过布尔运算符&
将它们组合成一个矩阵。以上是关于组中多列的R元素到元素操作的主要内容,如果未能解决你的问题,请参考以下文章
如何使用没有临时表的 SQL 查询为组中的每个元素添加序列号