如何引用函数内变量中保存的多个列名

How to refer to multiple column names held in a variable inside a function

这来自

按照建议,我将单独发布其他请求。先码后问。

library(data.table)

# load the data
customers <- structure(list(
  NAME = c("B V RAMANA  ", "K KRISHNA", "B SUDARSHAN", "B ANNAPURNA ",
           "BIKASH BAHADUR CHITRE", "KOTLA CHENNAMMA ", "K KRISHNA",
           "  B V RAMANA", "B ANNAPURNA", "ZAITOON BEE", "BIMAN BALAIAH",
           " KOTLA CHENNAMMA ", "B V RAMANA"),
  DOB = c("15-01-1960", "01-05-1964", "12-03-1975", "12-12-1962",
          "14-05-1983", "15-07-1958", "01-05-1964", "15-01-1960",
          "12-12-1962", "20-02-1960", "10-03-1964", "15-07-1958",
          "15-01-1960"), 
  ID = c(" 502910", "502737", "502995", " 502878", "502984",
         "502466", "502737", "502902 ", "502877 ", "503000",
         "502979", "502467", "502902 "),
  PIN = c(500033, 500050, 500032, 500084, 500032, 500032, 500084, 500035,
          500084, 500084, 500032, 500032, 500032)), 
  .Names = c("NAME", "DOB", "ID", "PIN"),
  class = c("data.table", "data.frame"), row.names = c(NA, -13L))

# function for Duplicate Key Exclusion
dupKeyEx <- function(DT, dup_cols, unique_cols) {
  cols <-  c(dup_cols, unique_cols)
  mDT <-  DT[!duplicated(DT, by=cols), .N, by=dup_cols][N > 1L]
  ans <- unique(DT[mDT[, !"N"], on=dup_cols], by=cols)
  setorderv(ans, c(dup_cols, unique_cols))
  return(ans)
}

运行 由于 NAMEcustomers table 中的 ID 列的开头或结尾有空格,函数得到零结果:

dup_cols <- c("NAME", "DOB")
unique_cols <- "ID"
dupKeyEx(customers, dup_cols, unique_cols)
Empty data.table (0 rows) of 4 cols: NAME,DOB,ID,PIN

所以我们trim,即删除相关列两端的空格:

library(stringr)
customers[, `:=`(NAME = str_trim(NAME),
                 ID = str_trim(ID))]

现在我们得到了预期的结果:

dupKeyEx(customers, dup_cols, unique_cols)
              NAME        DOB     ID    PIN
1:     B ANNAPURNA 12-12-1962 502877 500084
2:     B ANNAPURNA 12-12-1962 502878 500084
3:      B V RAMANA 15-01-1960 502902 500035
4:      B V RAMANA 15-01-1960 502910 500033
5: KOTLA CHENNAMMA 15-07-1958 502466 500032
6: KOTLA CHENNAMMA 15-07-1958 502467 500032

我想知道 dup_colsunique_cols 中的列(一起分配在 dupKeyEx 函数内的 cols 变量中)是否可以 trimmed在函数本身内部。这样,在使用 dupKeyEx 函数之前,我就不需要记住 trim 相关的列了。

我进行了搜索,但无法找到在 cols 变量中引用列并在 dupKeyEx 函数中对它们应用 stringr::str_trim() 的方法。任何帮助将不胜感激。

你可以这样做:

dupKeyEx <- function(DT, dup_cols, unique_cols) {
  sapply(dup_cols,function(x) DT[[x]] <<- str_trim(DT[[x]]))
  cols <-  c(dup_cols, unique_cols)
  mDT <-  DT[!duplicated(DT, by=cols), .N, by=dup_cols][N > 1L]
  ans <- unique(DT[mDT[, !"N"], on=dup_cols], by=cols)
  setorderv(ans, c(dup_cols, unique_cols))
  return(ans)
}

或遵循@Frank 的建议,使用 data.table 语法。我们复制了table先不要修改输入:

dupKeyEx <- function(DT, dup_cols, unique_cols) {
  DT<-copy(DT) # comment if you want to keep changes by reference
  DT[, (dup_cols) := lapply(.SD, str_trim), .SDcols=dup_cols]
  cols <-  c(dup_cols, unique_cols)
  mDT <-  DT[!duplicated(DT, by=cols), .N, by=dup_cols][N > 1L]
  ans <- unique(DT[mDT[, !"N"], on=dup_cols], by=cols)
  setorderv(ans, c(dup_cols, unique_cols))
  return(ans)
}

San 编辑: 以下内容很好地满足了我的目的:

dupKeyEx <- function(DT, dup_cols, unique_cols) {
  cols <-  c(dup_cols, unique_cols)
  chr_cols <- cols[sapply(DT[, ..cols], is.character)]
  DT[, (chr_cols) := lapply(.SD, stringr::str_trim), .SDcols=chr_cols]
  mDT <-  DT[!duplicated(DT, by=cols), .N, by=dup_cols][N > 1L]
  ans <- unique(DT[mDT[, !"N"], on=dup_cols], by=cols)
  setorderv(ans, c(dup_cols, unique_cols))
  return(ans)
}

感谢两位贡献者。我修改了代码以仅将 str_trim 应用于字符列,以避免将其他列类型更改为字符。此更改是通过引用进行的,因为制作大型 tables 的副本会消耗包括时间在内的资源。此外,修整对我的分析工作没有不良影响 - 通常是必要的。

一般来说,在加载任何大 table 后,应立即通过以下方式修剪所有字符列:

trimCharCols <- function(DT) {
  colsDT <- names(DT)
  chr_cols <- colsDT[sapply(DT, is.character)]
  DT[, (chr_cols) := lapply(.SD, stringr::str_trim), .SDcols=chr_cols]
}

在这种情况下,可以避免使用 dupKeyEx 函数中的两行代码。但我暂时将它们留在那里,因为我需要这个函数是 "independent".