我有以下形式的 data.frame:

> set.seed(1)
> myp <- paste0('P', sort(sample(1:15, 10)))
> mydf <- data.frame(param=c(paste0(myp, 'B'), paste0(myp, 'R'), paste0(myp, 'max'), paste0(myp, 'min')),
+ value1=NA, value2=NA, value3=NA)
> rownames(mydf) <- mydf$param
> mydf$param <- NULL
> mydf
       value1 value2 value3
P1B        NA     NA     NA
P3B        NA     NA     NA
P4B        NA     NA     NA
P5B        NA     NA     NA
P6B        NA     NA     NA
P8B        NA     NA     NA
P9B        NA     NA     NA
P10B       NA     NA     NA
P11B       NA     NA     NA
P14B       NA     NA     NA
P1R        NA     NA     NA
P3R        NA     NA     NA
P4R        NA     NA     NA
P5R        NA     NA     NA
P6R        NA     NA     NA
P8R        NA     NA     NA
P9R        NA     NA     NA
P10R       NA     NA     NA
P11R       NA     NA     NA
P14R       NA     NA     NA
P1max      NA     NA     NA
P3max      NA     NA     NA
P4max      NA     NA     NA
P5max      NA     NA     NA
P6max      NA     NA     NA
P8max      NA     NA     NA
P9max      NA     NA     NA
P10max     NA     NA     NA
P11max     NA     NA     NA
P14max     NA     NA     NA
P1min      NA     NA     NA
P3min      NA     NA     NA
P4min      NA     NA     NA
P5min      NA     NA     NA
P6min      NA     NA     NA
P8min      NA     NA     NA
P9min      NA     NA     NA
P10min     NA     NA     NA
P11min     NA     NA     NA
P14min     NA     NA     NA

我想更新行的名称,为此我有一个如下所示的转换表:
> conv.df <- data.frame(name=myp, new.name=paste0('P', 1:10))
> conv.df
   name new.name
1    P1       P1
2    P3       P2
3    P4       P3
4    P5       P4
5    P6       P5
6    P8       P6
7    P9       P7
8   P10       P8
9   P11       P9
10  P14      P10

我唯一想做的就是更新 mydf 中的行名,以便它反射(reflect)转换表 new.names 中的 conv.df

这似乎很容易,但我无法解决它......我会尝试 regular expression 方法,我唯一的问题是我不是 100% 确定我只会遇到 rownamesPnBPnRPnmax 形式的 Pnmin 。 .. 我想要一个适用于任何 PnX 实例的解决方案(它总是 Pn 后跟 [:alpha:] )

最佳答案

您可以将行名设为一列,拆分根“Pn”和字母“[:alpha:]”,然后按如下方式重命名它们,

set.seed(1)
myp <- paste0('P', sort(sample(1:15, 10)))
mydf <- data.frame(param=c(paste0(myp, 'B'), paste0(myp, 'R'), paste0(myp, 'max'), paste0(myp, 'min')),
                     value1=NA, value2=NA, value3=NA)
rownames(mydf) <- mydf$param
mydf$param <- NULL
mydf


library(tidyverse)

mydf%>%
  rownames_to_column()%>%
  mutate(root = gsub("^(P\\d\\d?).*$","\\1",rowname),
         letter = gsub("^P\\d\\d?(.*)$","\\1",rowname))%>%
  mutate(root = recode(root,
    P1 = "P1",
    P3 = "P2",
    P4 = "P3",
    P5 = "P4",
    P6 = "P5",
    P8 = "P6",
    P9 = "P7",
    P10 = "P8",
    P11 = "P9",
    P14 = "P10"
  ))%>%
  mutate(rowname = paste0(root,letter))%>%
  column_to_rownames()%>%
  select(-root,-letter)

@teofil 的回答很好,而且很有效。这是通过仍然使用重新编码和一些元编程来做到这一点的另一种方法,
library(tidyverse)

rename_col_df <- function(data,colname,df_rename){
  # data is the input data frame
  # colname is the column to be modified
  # df_rename must have columns name and new.name

  colname = enexpr(colname) # Capture the user input col name as a symbol
  old_name = df_rename$name
  new_name = df_rename$new.name

  # Start construcing an expression
  # The following line creates a recode function
  # recode_expr[[1]] is "recode"
  # recode_expr[[2]] is the first argument
  recode_expr = expr(recode(!!colname))

  # All subsequent arguments to recode are added here

  for(i in seq_along(old_name)){
    recode_expr[[old_name[i]]] = new_name[i]
  }


  data = data %>% mutate(!!colname := !!recode_expr)

  return(data)

}

conv.df <- data.frame(name=myp, new.name=paste0('P', 1:10),stringsAsFactors = FALSE)

mydf%>%
  rownames_to_column()%>%
  mutate(root = gsub("^(P\\d\\d?).*$","\\1",rowname),
         letter = gsub("^P\\d\\d?(.*)$","\\1",rowname))%>%
  rename_col_df(root,conv.df) %>%
  mutate(rowname = paste0(root,letter))%>%
  column_to_rownames()%>%
  select(-root,-letter)

如果我们想将重命名应用于向量而不是数据帧,
rename_vec_df <- function(vec,df_rename){
  # vec is the vector to be modified
  # df_rename must have columns name and new.name

  old_name = df_rename$name
  new_name = df_rename$new.name

  # Start construcing an expression
  # The following line creates a recode function
  # recode_expr[[1]] is "recode"
  # recode_expr[[2]] is the first argument
  recode_expr = expr(recode(!!vec))

  # All subsequent arguments to recode are added here

  for(i in seq_along(old_name)){
    recode_expr[[old_name[i]]] = new_name[i]
  }


  vec = eval(recode_expr)

  return(vec)

}

myp <- paste0('P', sort(sample(1:15, 10)))
conv.df <- data.frame(name=myp, new.name=paste0('P', 1:10),stringsAsFactors = FALSE)

vec <- c("P1","P14","P10")

rename_vec_df(vec,conv.df)

要了解有关此处使用的技术的更多信息,

https://rlang.r-lib.org/reference/quotation.html
https://adv-r.hadley.nz/metaprogramming.html

关于R:使用转换表更新 data.frame 中的行名,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57751296/

10-12 18:27