我想编写一个函数(最好是R,但欢迎使用其他语言),它可以识别数据集中列(限于加法/减法)之间的关系。这样做的一个实际应用是在大型多列金融数据集上运行它,其中一些列是其他列的小计 - 并识别这样的小计。
理想情况下,我想允许小的差异 - 例如允许舍入问题导致列不完全相加100%。
我找到了以下question,其中包括一个涉及矩阵和排名的解决方案,但我不确定是否有任何方法可以处理因舍入问题而产生的数据噪音。
举个例子:
d = data.frame(a=c(10.12, 20.02, 30.08, 20.19), b=c(12.12, 20.45, 20.52, 16.72), c=c(11, 123.25, 20.67, 20.78))
d$d = d$a + d$b
d$e = d$d + d$c
> d
a b c d e
1 10.12 12.12 11.00 22.24 33.24
2 20.02 20.45 123.25 40.47 163.72
3 30.08 20.52 20.67 50.60 71.27
4 20.19 16.72 20.78 36.91 57.69
magic_function(d)
[1] "d$d = d$a + d$b"
[2] "d$e = d$d + d$c" # or "d$e = d$a + d$b + d$c" (first option preferred)
链接问题中的解决方案很有效,直到我将噪声引入等式。例如d$d[[4]] = d$d[[4]] + 0.01
- 然后它根本不再有效。我的问题是:
答案 0 :(得分:0)
如果你只需要检查任何列是否是任何其他两个总和的结果,这是一个可行的想法。它还允许您添加噪音。我们基本上首先通过添加原始数据集的所有组合来创建数据框。然后,我们用创建的数据框减去每列数据集。如果所有值都为0,则表示它们匹配。通过使用colSums(i < 0.01) == nrow(i))
,我们可以添加所需的噪音。
d2 <- setNames(data.frame(combn(1:ncol(d), 2, function(i) rowSums(d[i]))),
combn(names(d), 2, function(j)paste(j, collapse = ' + ')))
l1 <- lapply(d, function(i) sapply(d2, function(j) Map(function(x, y)abs(x - y), i, j)))
lapply(l1, function(i) names(which(colSums(i < 0.01) == nrow(i))))
#$a
#character(0)
#$b
#character(0)
#$c
#character(0)
#$d
#[1] "a + b"
#$e
#[1] "c + d"
或者将其设为noise
作为输入参数的函数,
f1 <- function(df, noise){
d2 <- setNames(data.frame(combn(1:ncol(df), 2, function(i) rowSums(df[i]))),
combn(names(df), 2, function(j)paste(j, collapse = ' + ')))
l1 <- lapply(df, function(i) sapply(d2, function(j)
Map(function(x, y)abs(x - y), i, j)))
Filter(length, lapply(l1, function(i)
names(which(colSums(i < noise) == nrow(i)))))
}
f1(d, 0.01)
#$d
#[1] "a + b"
#$e
#[1] "c + d"
如果我们想让它更灵活,那么我们可以添加另一个参数来取组合数(列数),即
f1 <- function(df, n, noise){
d2 <- setNames(data.frame(combn(1:ncol(df), n, function(i) rowSums(df[i]))),
combn(names(df), n, function(j)paste(j, collapse = ' + ')))
l1 <- lapply(df, function(i) sapply(d2, function(j)
Map(function(x, y)abs(x - y), i, j)))
Filter(length, lapply(l1, function(i)
names(which(colSums(i < noise) == nrow(i)))))
}
sapply(2:3, function(i) f1(d, i, 0.01))
#[[1]]
#[[1]]$d
#[1] "a + b"
#[[1]]$e
#[1] "c + d"
#[[2]]
#[[2]]$e
#[1] "a + b + c"
答案 1 :(得分:0)
如果允许总和仅用于连续列,并且仅用于以前的值,则计算工作量可能适用于10-20列。此过程检查列是否等于先前连续列的总和,并允许一些错误:
d <- data.frame(a=c(10.12, 20.02, 30.08, 20.19),
b=c(12.12, 20.45, 20.52, 16.72),
c=c(11, 123.25, 20.67, 20.78));
d$d <- round(d$a + d$b + runif(4,0,0.04),2);
d$e <- round(d$d + d$c + runif(4,0,0.04),2);
## Assumptions:
## * sum columns relate to previous values only
## * sum columns relate to consecutive columns
sumColumns <- NULL;
allowedError <- 0.05;
for(col in 3:ncol(d)){
for(subStart in 1:(col-2)){
for(subEnd in (subStart+1):(col-1)){
if(all(abs(d[,col] - rowSums(d[,subStart:subEnd, drop=FALSE])) <
allowedError)){
cat(sprintf("Column %d is a sum of columns %d-%d\n",
col, subStart, subEnd));
sumColumns[col] <- TRUE;
}
}
}
}
输出:
Column 4 is a sum of columns 1-2
Column 5 is a sum of columns 3-4
这可以修改为允许连续列和任意数量的总和列,同时保持易处理性(假设总和列的数量保持较低)。这种修改并非完全无足轻重,而是留给读者的练习。