首页 > 解决方案 > 如何在多列上使用提取并根据输入列名称命名输出列

问题描述

我有以下形式的血压数据数据框:

bpdata <- data.frame(bp1 = c("120/89", "110/70", "121/78"), bp2 = c("130/69", "120/90", "125/72"), bp3 = c("115/90", "112/71", "135/80"))

我想使用以下提取命令,但在全局范围内,即在所有 bp\d 列上

extract(bp1, c("systolic_1","diastolic_1"),"(\\d+)/(\\d+)")

如何捕获列选择中的数字并在列输出名称中使用它?我可以通过创建列名列表然后使用其中一个 apply 系列来解决这个问题,但在我看来,应该有一种更优雅的方式来做到这一点。

有什么建议么?

标签: rdplyr

解决方案


我们可以read.csv在循环中的多个列上使用 ( Map) withsep = "/"cbind最后的list元素do.call

do.call(cbind, Map(function(x, y) read.csv(text= x, sep="/", header = FALSE,
    col.names = paste0(c('systolic', 'diastolic'), y)),
        unname(bpdata), seq_along(bpdata)))

#    systolic1 diastolic1 systolic2 diastolic2 systolic3 diastolic3
#1       120         89       130         69       115         90
#2       110         70       120         90       112         71
#3       121         78       125         72       135         80

或者没有循环,paste将每行的列转换为单个字符串,然后使用read.csv/read.table

read.csv(text = do.call(paste, c(bpdata, sep="/")), 
   sep="/", header = FALSE, 
   col.names = paste0(c('systolic', 'diastolic'), 
          rep(seq_along(bpdata), each = 2)))
#  systolic1 diastolic1 systolic2 diastolic2 systolic3 diastolic3
#1       120         89       130         69       115         90
#2       110         70       120         90       112         71
#3       121         78       125         72       135         80

或使用tidyverse,类似的选项是unite将列分成一个 with /,然后使用extractseparate将列拆分为多个列

library(dplyr)
library(tidyr)
library(stringr)
bpdata %>% 
    unite(bpcols, everything(), sep="/") %>% 
    separate(bpcols, into = str_c(c('systolic', 'diastolic'), 
       rep(seq_along(bpdata), each = 2)), convert = TRUE)
#  systolic1 diastolic1 systolic2 diastolic2 systolic3 diastolic3
#1       120         89       130         69       115         90
#2       110         70       120         90       112         71
#3       121         78       125         72       135         80

推荐阅读