我正在寻找一种方法来确定data.frame
中的候选键。
举个简单的例子,如果我有data.frame
:
df <- data.frame(Col1 = c("A", "A", "B", "B", "C", "C"), Col2 = c(1, 2, 1, 2, 1, 2))
然后显然Col1或Col2不是单独唯一标识每一行的键,但Col1+Col2
的串联将是。
通过比较length(unique(df$column)) == nrow(df)
可以找到可以作为密钥的单个列。
但是如果我的data.frame
包含许多列而没有单个列是关键字,那么可能会将两列连接在一起。
问题是,我怎样才能找出哪两个会起作用呢?哪三个?我意识到这可能是一个指数级增长的详尽搜索,但我想知道是否有更好的方法。
我编写代码至少搜索所有可能的2列组合,但这非常麻烦。
答案 0 :(得分:1)
虽然我并不完全清楚以这种方式寻找钥匙的动机是什么,但我认为确定哪些特征组合可以唯一地识别人口中的个体是有趣的。
正如您所指出的,详尽的搜索可能非常昂贵,因为您需要检查2^k
个k
个变量的子集。不过,它很容易编码并为运行时提供基准:
all.keys <- function(dat) {
combos <- tail(expand.grid(sapply(dat, function(x) c(F, T), simplify=FALSE)), -1)
nunique <- unlist(apply(combos, 1, function(x) nrow(unique(dat[,x,drop=FALSE]))))
combos[nunique == nrow(dat),]
}
对于11列mtcars
数据集,这将在大约半秒内运行,并返回可用作键的1,276种不同的列组合;没有单个列可以用作密钥,但可以使用9对列。
dim(all.keys(mtcars))
# [1] 1276 11
head(all.keys(mtcars))
# mpg cyl disp hp drat wt qsec vs am gear carb
# 34 TRUE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
# 36 TRUE TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
# 38 TRUE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
# 40 TRUE TRUE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
# 42 TRUE FALSE FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
# 44 TRUE TRUE FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
table(rowSums(all.keys(mtcars)))
# 2 3 4 5 6 7 8 9 10 11
# 9 52 148 266 322 266 148 53 11 1
对于具有多列的数据集,可能无法有效地计算所有可能的密钥,因为有效密钥的数量可能会以变量的数量呈指数级增长。我们可能有效地找到最小的密钥大小(在这种情况下,大小为2的密钥)。一种直接的方法是循环键大小,并在找到该大小的有效密钥后停止:
small.keys <- function(dat) {
for (size in 1:ncol(dat)) {
keys <- combn(names(dat), size)
nunique <- apply(keys, 2, function(x) nrow(unique(dat[,x,drop=FALSE])))
if (sum(nunique == nrow(dat)) > 0) {
return(t(keys[,nunique == nrow(dat)]))
}
}
return(NULL)
}
这在我的计算机上运行不到10毫秒(比mtcars的详尽方法快50倍)并返回大小为2的9个键:
small.keys(mtcars)
# [,1] [,2]
# [1,] "mpg" "wt"
# [2,] "mpg" "qsec"
# [3,] "cyl" "qsec"
# [4,] "disp" "qsec"
# [5,] "hp" "qsec"
# [6,] "drat" "qsec"
# [7,] "wt" "qsec"
# [8,] "qsec" "am"
# [9,] "qsec" "carb"
当然,如果唯一有效的密钥很大或者没有有效密钥,这仍然会表现不佳,因为在这种情况下我们仍需要详尽检查所有变量子集。