首页 > 解决方案 > 如何使用 **purrr** pacakge 中的 `map` 系列命令在数据框中的行之间交换列?

问题描述

想象一下桌子上有 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



标签: rdictionaryvectorizationtidyversepurrr

解决方案


你可以使用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在这里用来删除名称。


推荐阅读