这是从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
表中ID
和customers
列的开头或结尾处的空格,运行该函数的结果为零:
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_cols
和unique_cols
中的列(cols
函数中的dupKeyEx
变量中的列一起)是否可以在函数内部进行修剪。这样,在使用dupKeyEx
函数之前,我不需要记住修剪相关列。
我进行了搜索,但无法找到引用cols
变量中的列的方法,并在stringr::str_trim()
函数内对其应用dupKeyEx
。任何帮助将不胜感激。
答案 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
函数的两行代码。但是我暂时将它们留在那里因为我需要这个功能是“独立的”。