如何使用 **purrr** 包中的 `map` 系列命令在数据框中跨行交换列?
how to use the `map` family command in **purrr** pacakge to swap the columns across rows in data frame?
假设桌子上有 4 张卡片,并且有几排(例如,演示中有 5 排)。每张牌的价值已经列在演示数据框中。但是,卡片的确切位置由 pos 列索引,请参阅下面我生成的演示数据。
为此,我使用 []
函数跨行交换卡片,以将卡片的值切换回其原始位置。下面的代码已经实现了这样的目的。为了避免显式使用循环,我想知道如果我将向量化函数与来自 tidyverse 系列的包一起使用,是否可以达到类似的效果,例如pmap 或包内的相关函数 purrr?
# 1. data generation ------------------------------------------------------
rm(list=ls())
vect<-matrix(round(runif(20),2),nrow=5)
colnames(vect)<-paste0('card',1:4)
order<-rbind(c(2,3,4,1),c(3,4,1,2),c(1,2,3,4),c(4,3,2,1),c(3,4,2,1))
colnames(order)=paste0('pos',1:4)
dat<-data.frame(vect,order,stringsAsFactors = F)
# 2. data swap ------------------------------------------------------------
for (i in 1:dim(dat)[1]){
orders=dat[i,paste0('pos',1:4)]
card=dat[i,paste0('card',1:4)]
vec<-card[order(unlist(orders))]
names(vec)=paste0('deck',1:4)
dat[i,paste0('deck',1:4)]<-vec
}
dat
你可以使用 pmap_dfr
:
card_cols <- grep('card', names(dat))
pos_cols <- grep('pos', names(dat))
dat[paste0('deck', seq_along(card_cols))] <- purrr::pmap_dfr(dat, ~{
x <- c(...)
as.data.frame(t(unname(x[card_cols][order(x[pos_cols])])))
})
dat
# card1 card2 card3 card4 pos1 pos2 pos3 pos4 deck1 deck2 deck3 deck4
#1 0.05 0.07 0.16 0.86 2 3 4 1 0.86 0.05 0.07 0.16
#2 0.20 0.98 0.79 0.72 3 4 1 2 0.79 0.72 0.20 0.98
#3 0.50 0.79 0.72 0.10 1 2 3 4 0.50 0.79 0.72 0.10
#4 0.03 0.98 0.48 0.06 4 3 2 1 0.06 0.48 0.98 0.03
#5 0.41 0.72 0.91 0.84 3 4 2 1 0.84 0.91 0.41 0.72
这里要注意的一件事是确保 pmap
函数的输出没有列的原始名称。如果它们有原始名称,它会根据名称重新排列列,并且输出的顺序不会正确。我在这里使用 unname
来删除名称。
假设桌子上有 4 张卡片,并且有几排(例如,演示中有 5 排)。每张牌的价值已经列在演示数据框中。但是,卡片的确切位置由 pos 列索引,请参阅下面我生成的演示数据。
为此,我使用 []
函数跨行交换卡片,以将卡片的值切换回其原始位置。下面的代码已经实现了这样的目的。为了避免显式使用循环,我想知道如果我将向量化函数与来自 tidyverse 系列的包一起使用,是否可以达到类似的效果,例如pmap 或包内的相关函数 purrr?
# 1. data generation ------------------------------------------------------
rm(list=ls())
vect<-matrix(round(runif(20),2),nrow=5)
colnames(vect)<-paste0('card',1:4)
order<-rbind(c(2,3,4,1),c(3,4,1,2),c(1,2,3,4),c(4,3,2,1),c(3,4,2,1))
colnames(order)=paste0('pos',1:4)
dat<-data.frame(vect,order,stringsAsFactors = F)
# 2. data swap ------------------------------------------------------------
for (i in 1:dim(dat)[1]){
orders=dat[i,paste0('pos',1:4)]
card=dat[i,paste0('card',1:4)]
vec<-card[order(unlist(orders))]
names(vec)=paste0('deck',1:4)
dat[i,paste0('deck',1:4)]<-vec
}
dat
你可以使用 pmap_dfr
:
card_cols <- grep('card', names(dat))
pos_cols <- grep('pos', names(dat))
dat[paste0('deck', seq_along(card_cols))] <- purrr::pmap_dfr(dat, ~{
x <- c(...)
as.data.frame(t(unname(x[card_cols][order(x[pos_cols])])))
})
dat
# card1 card2 card3 card4 pos1 pos2 pos3 pos4 deck1 deck2 deck3 deck4
#1 0.05 0.07 0.16 0.86 2 3 4 1 0.86 0.05 0.07 0.16
#2 0.20 0.98 0.79 0.72 3 4 1 2 0.79 0.72 0.20 0.98
#3 0.50 0.79 0.72 0.10 1 2 3 4 0.50 0.79 0.72 0.10
#4 0.03 0.98 0.48 0.06 4 3 2 1 0.06 0.48 0.98 0.03
#5 0.41 0.72 0.91 0.84 3 4 2 1 0.84 0.91 0.41 0.72
这里要注意的一件事是确保 pmap
函数的输出没有列的原始名称。如果它们有原始名称,它会根据名称重新排列列,并且输出的顺序不会正确。我在这里使用 unname
来删除名称。