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

时间:2017-08-16 14:53:20

标签: r data.table stringr

这是从Extract rows with duplicate values in two or more fields but different values in another field

开始的

根据建议,我会另外发布附加请求。然后第一个代码问题。

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)
}

由于NAME表中IDcustomers列的开头或结尾处的空格,运行该函数的结果为零:

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

因此我们修剪,即从相关列的两端删除空格:

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中的列(cols函数中的dupKeyEx变量中的列一起)是否可以在函数内部进行修剪。这样,在使用dupKeyEx函数之前,我不需要记住修剪相关列。

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

1 个答案:

答案 0 :(得分:1)

你可以这样做:

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)
}

或使用data.table语法关注@ Frank的建议。我们首先制作表格的副本,不要修改输入:

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,以避免将其他列类型更改为字符。此更改是通过引用进行的,因为制作大表的副本会花费包括时间在内的资源。此外,修剪在我的分析工作中没有不良副作用 - 通常是必要的。

一般来说,修剪所有字符列应该在加载任何大表后立即完成:

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函数的两行代码。但是我暂时将它们留在那里因为我需要这个功能是“独立的”。