首页 > 解决方案 > 结合 {stringr} 和 mutate() 在大型数据集中一次操作多个列?

问题描述

代表

df <- tibble(name = c("Person_1","Person_2","Person_3"),
             `AxxBxx1:0` = c("1:04","2:02","0:1"),
             `AxxCxx5:0` = c("5:04","3:02","0:0"),
             `BxxCxx2:1` = c("2:14","1:03","0:1"))

目标是将此 data.frame 转换为另一个,其中以 结尾的变量_real取自列名,并且_bet来自_result变量df值的第一和第二部分:

df_2 <- tibble(name = c("Person_1","Person_2","Person_3"),
               AxxBxx_real = "1:0",
               AxxCxx_real = "5:0",
               BxxCxx_real = "2:1",
               AxxBxx_bet = c("1:0","2:0","0:1"),
               AxxCxx_bet = c("5:0","3:0","0:0"),
               BxxCxx_bet = c("2:1","1:0","0:1"),
               AxxBxx_result = c("4","2",""),
               AxxCxx_result = c("4","2",""),
               BxxCxx_result = c("4","3",""))

问题:真实的数据集比理想的数据集要大得多df,理想情况下我希望尽可能地自动化df转换df_2

代码(即我到目前为止所做的)

library(tidyverse)

# Step 1: Get real match results from variable names.
df$AxxBxx_real <- "1:0"
df$AxxCxx_real <- "5:0"
df$BxxCxx_real <- "2:1"

有没有办法一次mutate()将原始变量从这df三个_real变量中提取出来,而无需查找单个匹配结果?mutate(names(df)[2:4] = str_extract(...))或类似的事情显然不起作用。

# Create `_bet` and `_result` variables.
str_remove(names(df)[2:4], "[0-99]:[0-99]") %>%
  paste0("_bet") -> names(df)[2:4]

df %>%
  mutate(AxxBxx_result = AxxBxx_bet,
         AxxCxx_result = AxxCxx_bet,
         BxxCxx_result = BxxCxx_bet) -> df

df$AxxBxx_bet <- str_extract(df$AxxBxx_bet, "[0-99]:[0-99]")
df$AxxCxx_bet <- str_extract(df$AxxCxx_bet, "[0-99]:[0-99]")
df$BxxCxx_bet <- str_extract(df$BxxCxx_bet, "[0-99]:[0-99]")

df$AxxBxx_result <- str_remove(df$AxxBxx_result, "[0-99]:[0-99]")
df$AxxCxx_result <- str_remove(df$AxxCxx_result, "[0-99]:[0-99]")
df$BxxCxx_result <- str_remove(df$BxxCxx_result, "[0-99]:[0-99]")

这里的问题是,虽然将赌注从 data.frame 中每个人为他或她的赌注获得的结果中分离出来的过程在某种程度上是标准化的,但创建和存储新变量的方式却不是。我不想单独为每个变量执行此操作,而是希望自动完成此操作。取原始变量的名称并从它们的名称中删除结果,然后拆分为_bet_real。同样,问题是我一次只能使用mutate()任何给定的变量。有没有更好、更省时的方法?

标签: rstringrdplyr

解决方案


tidyr这是使用library执行此操作的一种方法:

这将获取长格式的数据,将列名分为两部分,使用extract我们将值分成两列,最后以宽格式获取数据。

我建议您一次运行这一步,以了解这里发生了什么。

library(tidyr)

df %>%
  pivot_longer(cols = -name, 
               names_to = c('col1', 'real'), 
               names_pattern = '([A-Za-z]+)(\\d+:\\d+)') %>%
  extract(value, c('bet', 'result'), '(\\d+:.)(.)?') %>%
  pivot_wider(names_from = col1, values_from = c(real, bet, result), 
              names_glue = '{col1}_{.value}')

#  name     AxxBxx_real AxxCxx_real BxxCxx_real AxxBxx_bet AxxCxx_bet BxxCxx_bet AxxBxx_result AxxCxx_result BxxCxx_result
#  <chr>    <chr>       <chr>       <chr>       <chr>      <chr>      <chr>      <chr>         <chr>         <chr>        
#1 Person_1 1:0         5:0         2:1         1:0        5:0        2:1        "4"           "4"           "4"          
#2 Person_2 1:0         5:0         2:1         2:0        3:0        1:0        "2"           "2"           "3"          
#3 Person_3 1:0         5:0         2:1         0:1        0:0        0:1        ""            ""            ""      

我不确定为什么namePerson_1, Person_2,Person_3输入变为A,BC输出。我在这里保持相同的名字。


推荐阅读