首页 > 解决方案 > 根据正则表达式匹配创建新列

问题描述

问题

我想使用以下公式为相对标准偏差创建一个新列:stdev * 100 / abs(mean). 我有超过 40 个变量,每个变量都有自己的stdevmean(所以 80 列)。我想做的是使用正则表达式根据前面的名称计算两列(stdev和)的相对标准偏差。mean例如,对于列AceticAcid.stdevAceticAcid.mean,计算相对标准偏差以自动创建新列AcetiAcid.rsd。方程为:AceticAcid.stdev * 100 / abs(AceticAcid.mean)


示例数据框

print(df)

  AceticAcid.mean AceticAcid.stdev Glucose.mean Glucose.stdev Propanol.mean Propanol.stdev
1        28.75775         0.911130     48.27333     4.4991249      144.4770       38.34122
2        78.83051        10.562110     28.13337     1.2304387      134.6402       31.76264
3        40.89769        17.848381     37.10283     0.2102977      132.0253       33.76568
4        88.30174        11.028700     32.90534     1.6396036      149.7135       21.56639
5        94.04673         9.132295     14.11699     4.7725182      132.7853       15.88455

期望的输出(不关心新列的顺序)

print(df_rsd)

  AceticAcid.mean AceticAcid.stdev Glucose.mean Glucose.stdev Propanol.mean Propanol.stdev AceticAcid.rsd Glucose.rsd Propanol.rsd
1        28.75775         0.911130     48.27333     4.4991249      144.4770       38.34122       3.168294   9.3201039     26.53795
2        78.83051        10.562110     28.13337     1.2304387      134.6402       31.76264      13.398504   4.3735921     23.59076
3        40.89769        17.848381     37.10283     0.2102977      132.0253       33.76568      43.641536   0.5667969     25.57515
4        88.30174        11.028700     32.90534     1.6396036      149.7135       21.56639      12.489788   4.9827894     14.40511
5        94.04673         9.132295     14.11699     4.7725182      132.7853       15.88455       9.710380  33.8069175     11.96258

重复尝试...... 我不想把这些写出 40 次(必须有一个很好的正则表达式来实现这一点):

df_rsd <- df %>% mutate(AceticAcid.rsd = AceticAcid.stdev * 100 / abs(AceticAcid.mean),
                        Glucose.rsd = Glucose.stdev * 100 / abs(Glucose.mean),
                        Propanol.rsd = Propanol.stdev * 100 / abs(Propanol.mean))

可重现的数据

structure(list(AceticAcid.mean = c(28.7577520124614, 78.8305135443807, 
40.89769218117, 88.3017404004931, 94.0467284293845), AceticAcid.stdev = c(0.911129987798631, 
10.5621097609401, 17.8483808878809, 11.0287002893165, 9.13229470606893
), Glucose.mean = c(48.2733338139951, 28.1333662476391, 37.1028254181147, 
32.9053360782564, 14.1169873066247), Glucose.stdev = c(4.49912485200912, 
1.2304386717733, 0.210297667654231, 1.63960359641351, 4.77251824573614
), Propanol.mean = c(144.476965803187, 134.64017030783, 132.025340688415, 
149.713488831185, 132.785289955791), Propanol.stdev = c(38.3412187267095, 
31.7626409884542, 33.7656808178872, 21.5663894917816, 15.884545892477
)), class = "data.frame", row.names = c(NA, -5L))

标签: rregexdplyr

解决方案


我们可以根据删除列名的后缀部分split.default将数据集拆分为一个listdata.frame 列,然后遍历listwith lapply,进行计算并将其分配给“df”中的新列

out <- lapply(split.default(df, sub("\\..*", "", names(df))), 
          function(x) x[[2]]* 100/abs(x[[1]]))
df[paste0(names(out), ".rsd")] <- out

df
#  AceticAcid.mean AceticAcid.stdev Glucose.mean Glucose.stdev Propanol.mean Propanol.stdev AceticAcid.rsd Glucose.rsd Propanol.rsd
#1        28.75775         0.911130     48.27333     4.4991249      144.4770       38.34122       3.168294   9.3201039     26.53795
#2        78.83051        10.562110     28.13337     1.2304387      134.6402       31.76264      13.398504   4.3735921     23.59076
#3        40.89769        17.848381     37.10283     0.2102977      132.0253       33.76568      43.641536   0.5667969     25.57515
#4        88.30174        11.028700     32.90534     1.6396036      149.7135       21.56639      12.489788   4.9827894     14.40511
#5        94.04673         9.132295     14.11699     4.7725182      132.7853       15.88455       9.710380  33.8069175     11.96258

或与tidyverse

library(purrr)
library(dplyr)
library(stringr)
df %>% 
  split.default(str_remove(names(.), "\\..*")) %>%
  map_dfc(~ .x[[2]] * 100/abs(.x[[1]])) %>% 
  rename_all(~ str_c(., '.rsd')) %>% 
  bind_cols(df, .)

推荐阅读