如何识别数据集中其他列总和的列

时间:2017-04-24 19:44:33

标签: r matrix linear-algebra

我想编写一个函数(最好是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 - 然后它根本不再有效。我的问题是:

  1. 是否有其他方法可以识别之间的关系 列(特别是如果它们仅限于简单 加/减)
  2. 是否有任何方法可以解决     不完美的数据质量问题或我是否需要构建一些额外的     它的功能(例如,在通过秩识别算法运行之前对数据进行舍入)。

2 个答案:

答案 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

这可以修改为允许连续列和任意数量的总和列,同时保持易处理性(假设总和列的数量保持较低)。这种修改并非完全无足轻重,而是留给读者的练习。