R 取消列出/取消列出列到多个列中
我知道在数据帧中取消列表列的测试的问题已经被提出并回答了多次。然而,这里是潜在的237。这类问题 我有以下数据:R 取消列出/取消列出列到多个列中,r,list,unnest,R,List,Unnest,我知道在数据帧中取消列表列的测试的问题已经被提出并回答了多次。然而,这里是潜在的237。这类问题 我有以下数据: set.seed(666) dat <- data.frame(sysRespNum = c(1,2,3,4,5,6), product1 = sqrt(rnorm(6, 20, 5)^2), product2 = sqrt(rnorm(6, 20, 5)^2),
set.seed(666)
dat <- data.frame(sysRespNum = c(1,2,3,4,5,6),
product1 = sqrt(rnorm(6, 20, 5)^2),
product2 = sqrt(rnorm(6, 20, 5)^2),
product3 = sqrt(rnorm(6, 20, 5)^2))
现在,我想计算每个产品在所有产品总和中的比例,因此我想计算product1/sum(我的三个产品)
,然后计算产品2和3的比例。所以我期待有三个新专栏
我尝试了以下方法:
library(tidyverse)
dat %>%
mutate(sum_Product = apply(across(-sysRespNum), 1, function(x) list(sum_Product = x/sum(x))))
(旁白:是否有一种更直接的方法可以直接对其进行变异,而无需创建列表。我现在可以先创建一个求和列,然后再进行简单的变异和交叉。但我想知道是否可以在不创建临时求和列的情况下实现计算)
现在我的问题是很难取消测试sum\u Product
list列unnest\u-wide
不起作用,sum\u-Product
列仍然是一个列表
所以对我来说唯一有效的就是
- 遵循此解决方案:
- 更改上面的“我的代码”,并将
部分替换为列表
:数据框
dat %>%
mutate(sum_Product = apply(across(-sysRespNum), 1, function(x) data.frame(sum_Product = x/sum(x)))) %>%
unnest(cols = everything()) %>%
mutate(product = rep(1:3, nrow(.)/3)) %>%
pivot_wider(values_from = sum_Product,
names_from = product,
names_prefix = "share_product")
这给出了正确的结果:
# A tibble: 6 x 7
sysRespNum product1 product2 product3 share_product1 share_product2
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 23.8 13.5 24.3 0.386 0.219
2 2 30.1 16.0 11.4 0.523 0.278
3 3 18.2 11.0 20.7 0.365 0.221
4 4 30.1 19.8 19.6 0.433 0.285
5 5 8.92 30.8 24.3 0.139 0.481
6 6 23.8 11.1 21.7 0.420 0.197
# … with 1 more variable: share_product3 <dbl>
#一个tible:6 x 7
sysRespNum product1 product2 product3 share\U product1 share\U product2
1 1 23.8 13.5 24.3 0.386 0.219
2 2 30.1 16.0 11.4 0.523 0.278
3 3 18.2 11.0 20.7 0.365 0.221
4 4 30.1 19.8 19.6 0.433 0.285
5 5 8.92 30.8 24.3 0.139 0.481
6 6 23.8 11.1 21.7 0.420 0.197
#…还有1个变量:share_product3
然而,感觉没有必要把所有的东西都卸下,然后用pivot_进行重塑
因此,a)是否有一种更优雅的方法来计算我的共享变量,b)是否有一种更优雅/更短/更不冗长的方法来将列表列重塑为多个向量列?更容易做到这一点
rowSums
,即在以关键字“product”开头的列上,将“product1”除以rowSums
。与使用跨c_
的rowwise
不同,这是矢量化的,应该也很快
library(dplyr)
dat %>%
mutate(sum_product = product1/rowSums(select(., starts_with('product'))))
注意:base R
代码(apply
)和跨的tidyverse选项混合使用,这似乎不是最佳方式
如果我们需要对所有“产品”列执行此操作,请首先使用mutate
创建一个sum
列,然后在以“产品”开头的列上使用cross
将该列除以“sum\u col”
dat %>%
mutate(Sum_col = rowSums(select(., starts_with('product'))),
across(starts_with('product'),
~ ./Sum_col, .names = '{.col}_sum_product')) %>%
select(-Sum_col)
-输出
#ysRespNum product1 product2 product3 product1_sum_product product2_sum_product product3_sum_product
#1 1 23.766555 13.46907 24.32327 0.3860783 0.2187998 0.3951219
#2 2 30.071773 15.98740 11.39922 0.5233660 0.2782431 0.1983909
#3 3 18.224328 11.03880 20.67063 0.3649701 0.2210688 0.4139610
#4 4 30.140839 19.78984 19.62087 0.4333597 0.2845348 0.2821054
#5 5 8.915628 30.75021 24.29150 0.1393996 0.4807925 0.3798079
#6 6 23.791981 11.14885 21.72450 0.4198684 0.1967490 0.3833826
或使用base R
nm1 <- startsWith(names(dat), 'product')
dat[paste0('sum_product', seq_along(nm1))] <- dat[nm1]/rowSums(dat[nm1])
nm1更容易做到这一点rowSums
,即在以关键字“product”开头的列上将“product1”除以rowSums
。与使用跨c_
的rowwise
不同,这是矢量化的,应该也很快
library(dplyr)
dat %>%
mutate(sum_product = product1/rowSums(select(., starts_with('product'))))
注意:base R
代码(apply
)和跨的tidyverse选项混合使用,这似乎不是最佳方式
如果我们需要对所有“产品”列执行此操作,请首先使用mutate
创建一个sum
列,然后在以“产品”开头的列上使用cross
将该列除以“sum\u col”
dat %>%
mutate(Sum_col = rowSums(select(., starts_with('product'))),
across(starts_with('product'),
~ ./Sum_col, .names = '{.col}_sum_product')) %>%
select(-Sum_col)
-输出
#ysRespNum product1 product2 product3 product1_sum_product product2_sum_product product3_sum_product
#1 1 23.766555 13.46907 24.32327 0.3860783 0.2187998 0.3951219
#2 2 30.071773 15.98740 11.39922 0.5233660 0.2782431 0.1983909
#3 3 18.224328 11.03880 20.67063 0.3649701 0.2210688 0.4139610
#4 4 30.140839 19.78984 19.62087 0.4333597 0.2845348 0.2821054
#5 5 8.915628 30.75021 24.29150 0.1393996 0.4807925 0.3798079
#6 6 23.791981 11.14885 21.72450 0.4198684 0.1967490 0.3833826
或使用base R
nm1 <- startsWith(names(dat), 'product')
dat[paste0('sum_product', seq_along(nm1))] <- dat[nm1]/rowSums(dat[nm1])
nm1我想下面的基本R代码应该适合您
cbind(
dat,
setNames(dat[-1] / rowSums(dat[-1]), paste0("share_product", seq_along(dat[-1])))
)
给
sysRespNum product1 product2 product3 share_product1 share_product2
1 1 23.766555 13.46907 24.32327 0.3860783 0.2187998
2 2 30.071773 15.98740 11.39922 0.5233660 0.2782431
3 3 18.224328 11.03880 20.67063 0.3649701 0.2210688
4 4 30.140839 19.78984 19.62087 0.4333597 0.2845348
5 5 8.915628 30.75021 24.29150 0.1393996 0.4807925
6 6 23.791981 11.14885 21.72450 0.4198684 0.1967490
share_product3
1 0.3951219
2 0.1983909
3 0.4139610
4 0.2821054
5 0.3798079
6 0.3833826
我想下面的基本R代码应该适合您
cbind(
dat,
setNames(dat[-1] / rowSums(dat[-1]), paste0("share_product", seq_along(dat[-1])))
)
给
sysRespNum product1 product2 product3 share_product1 share_product2
1 1 23.766555 13.46907 24.32327 0.3860783 0.2187998
2 2 30.071773 15.98740 11.39922 0.5233660 0.2782431
3 3 18.224328 11.03880 20.67063 0.3649701 0.2210688
4 4 30.140839 19.78984 19.62087 0.4333597 0.2845348
5 5 8.915628 30.75021 24.29150 0.1393996 0.4807925
6 6 23.791981 11.14885 21.72450 0.4198684 0.1967490
share_product3
1 0.3951219
2 0.1983909
3 0.4139610
4 0.2821054
5 0.3798079
6 0.3833826
好的,老的,普通的
rdat <- dat[-1]
rdat <- rdat/rowSums(rdat)
colnames(rdat) <- paste0("share_", colnames(rdat))
cbind(dat, rdat)
好的,老的,普通的
rdat <- dat[-1]
rdat <- rdat/rowSums(rdat)
colnames(rdat) <- paste0("share_", colnames(rdat))
cbind(dat, rdat)
是的,但这只给了我产品1的份额,而不是产品2和3的份额。我希望避免硬编码这三种产品中的每一种,因为在现实生活中,我在不同的用例中有不同数量的产品列。否则,我通常同意行和比较快。@deschen也许更新有助于youThanks akrun。是的,也考虑过这个解决方案(即首先创建一个包含总和的临时列),但是如果没有这个步骤,有一个直接的方法(即在我的帖子中,我有点排除了这个临时总和选项),我会感到惊讶。@deschen创建一个临时列比执行行总和
n timesYes更好,但这只给了我产品1的份额,而不是产品2和3的份额。我希望避免硬编码这三种产品中的每一种,因为在现实生活中,我在不同的用例中有不同数量的产品列。否则,我通常同意行和比较快。@deschen也许更新有助于youThanks akrun。是的,也考虑过这个解决方案(即首先创建一个包含总和的临时列),但是如果没有这个步骤,有一个直接的方法(即在我的帖子中,我有点排除了这个临时总和选项)。@deschen创建一个临时列比执行rowSums
n次它不是tidyverse,但是prop.table
应该做vars它不是tidyverse,但是prop.table
应该做vars