按元素比较两列

Compare two columns element-wise

我有一个大数据集 df(354903 行),其中有两列名为 df$ColumnNamedf$ColumnName.1

head(df)
       CompleteName       CompleteName.1
1   Lefebvre Arnaud Lefebvre Schuhl Anne
1.1 Lefebvre Arnaud              Abe Lyu
1.2 Lefebvre Arnaud              Abe Lyu
1.3 Lefebvre Arnaud       Louvet Nicolas
1.4 Lefebvre Arnaud   Muller Jean Michel
1.5 Lefebvre Arnaud  De Dinechin Florent

我正在尝试创建标签以查看名称是否相同。 当我尝试一个小子集时它起作用 [如果它们相同则为 1,如果不同则为 0]:

> match(df$CompleteName[1], df$CompleteName.1[1], nomatch = 0)
[1] 0
> match(df$CompleteName[1:10], df$CompleteName.1[1:10], nomatch = 0)
[1] 0 0 0 0 0 0 0 0 0 0

但是一旦我抛出完整的列,它就会给我完全不同的值,这对我来说似乎是胡说八道:

> match(df$CompleteName, df$CompleteName.1, nomatch = 0)
[1] 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101
[23] 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101
[45] 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101

我应该使用 sapply 吗?我没有弄清楚,我试过这个错误:

 sapply(df, function(x) match(x$CompleteName, x$CompleteName.1, nomatch = 0))

请帮忙!!!

来自 match 的手册页,

‘match’ returns a vector of the positions of (first) matches of its first argument in its second.

所以你的数据似乎表明 "Lefebvre Arnaud" 的第一个匹配项(第一个参数中的第一个位置)在第 101 行。我相信你打算做的是一个简单的比较,所以这是只是相等运算符 ==.

一些示例数据:

> a <- rep ("Lefebvre Arnaud", 6)
> b <- c("Abe Lyu", "Abe Lyu", "Lefebvre Arnaud", rep("De Dinechin Florent", 3))
> x <- data.frame(a,b, stringsAsFactors=F)
> x
            a                   b
1 Lefebvre Arnaud             Abe Lyu
2 Lefebvre Arnaud             Abe Lyu
3 Lefebvre Arnaud     Lefebvre Arnaud
4 Lefebvre Arnaud De Dinechin Florent
5 Lefebvre Arnaud De Dinechin Florent
6 Lefebvre Arnaud De Dinechin Florent
> x$a == x$b
[1] FALSE FALSE  TRUE FALSE FALSE FALSE

编辑: 此外,您需要确保您是在同类比较,因此请仔细检查列的数据类型。使用 str(df) 查看列是字符串还是因子。您可以使用 "stringsAsFactors = FALSE" 构造矩阵,也可以将因子转换为字符。有几种方法可以做到这一点,请在此处查看:Convert data.frame columns from factors to characters

正如其他人所指出的,match 不在这里。你想要的是平等,你可以通过 == 测试得到,这会给你 TRUE/FALSE。然后使用 as.numeric 将为您提供所需的 1/0 或使用 which 将为您提供索引。

但是您可能仍然对因素有疑问!

 # making up some similar data( adapted from earlier answer)
 a <- rep ("Lefebvre Arnaud", 6)
 b <- c("Abe Lyu", "Abe Lyu", "Lefebvre Arnaud", rep("De Dinechin Florent", 3))
 df <- data.frame(CompleteName = a, CompleteName.1 = b)
 which(df$CompleteName == df$CompleteName1)
 #integer(0)
 #Warning message:
 #In is.na(e2) : is.na() applied to non-(list or vector) of type 'NULL'

 str(df)
 # 'data.frame':    6 obs. of  2 variables:
 # $ CompleteName  : Factor w/ 1 level "Lefebvre Arnaud": 1 1 1 1 1 1
 # $ CompleteName.1: Factor w/ 3 levels "Abe Lyu","De Dinechin Florent",..: 1 1 3 2 2 2

stringsAsFactors

上面的 data.frame 不是用 stringsAsFactors=FALSE 构造的,因此导致了错误。不幸的是,开箱即用的 R 会将字符串强制转换为加载 csv 或创建 data.frame 的因素。这可以在创建 data.frame 时通过显式指定 stringsAsFactors=FALSE

来解决
df <- data.frame(CompleteName = a, CompleteName.1 = b, stringsAsFactors = FALSE)
df[which(df$CompleteName == df$CompleteName.1), ]
##     CompleteName CompleteName.1
## 3 Lefebvre Arnaud Lefebvre Arnaud

为避免将来出现此问题,请在 R 会话开始时 运行 options(stringsAsFactors = FALSE)(或将其放在 .R 脚本的顶部)。更多讨论在这里:

  • disable stringsAsFactors

这是一个使用 data.table 的解决方案,与 data.frame 解决方案的性能比较基于与您的情况相同的记录数。

col1 = sample(x = letters, size = 354903, replace = TRUE)
col2 = sample(x = letters, size = 354903, replace = TRUE)

library(data.table)
dt = data.table(col1 = col1, col2 = col2)
df = data.frame(col1 = col1, col2 = col2)

# comparing the 2 columns
system.time(dt$col1==dt$col2)
system.time(df$col1==df$col2)

# storing the comparison in the table/frame itself
system.time(dt[, col3:= (col1==col2)])
system.time({df$col3 = (df$col1 == df$col2)})

data.table 方法在我的机器上提供了显着的加速:从 0.020 秒到 0.008 秒。

亲自尝试看看。我知道这对于如此少的行数来说并不是很重要,但是将其乘以 1000,您会看到很大的不同!