Sql 使用线性最小二乘法匹配相似的数字集?

Sql 使用线性最小二乘法匹配相似的数字集?,sql,Sql,如果您有两组数字,请考虑: 刚毛: 还有一组更大的数字: 挫折: 目标是从两个集合中较大的集合中删除项目,这样两个集合中的项目数量相同,并且剩下的集合尽可能接近。我的想法是,我可以尝试每个项目的所有对,并最小化差异的平方。例如,我认为解决上述问题的办法是: SetA SetB Diff DiffSquared 10 15 5 25 20 20 0 0 30 35 5 25 40 40 0 0 Di

如果您有两组数字,请考虑:

刚毛:

还有一组更大的数字:

挫折:

目标是从两个集合中较大的集合中删除项目,这样两个集合中的项目数量相同,并且剩下的集合尽可能接近。我的想法是,我可以尝试每个项目的所有对,并最小化差异的平方。例如,我认为解决上述问题的办法是:

SetA  SetB   Diff  DiffSquared
10    15     5     25
20    20     0     0 
30    35     5     25
40    40     0     0

DiffSquaredSum == 50
这是解决方案,因为这是一个组合,将给你最小的DiffSquaredSum。我并不真的关心物品的配对,主要是把较大的一组物品裁剪成数量相同的一组,并且物品尽可能靠近。我意识到我可以用线性最小二乘的概念来解决这个问题,但我不确定从哪里开始编码这个问题。我更喜欢使用SQL,但我并不关心如何生成一个精确的解决方案,因为我了解了一个通用的方法,所以我可以判断这有多困难

我认为这基本上包括尝试两组的所有可能组合:

SetA  SetB   Diff  DiffSquared
10    15     5     25
20    20     0     0 
30    35     5     25
40    50     10    100

SetA  SetB   Diff  DiffSquared
10    15     5     25
20    20     0     0 
30    40     10    100
40    50     10    100
然后选择DiffSquared之和最小的组。我可能会先为SetA生成一个行数,然后为SetB生成一个行数,然后加入其中,这恰好给出了答案,但这只是巧合:

Row#    SetA  SetB
1        10    15
2        20    20 
3        30    35
4        40    40 
5       NULL   50
为了确定我找到了答案,我需要以某种方式反复这样做,并且有一个ID告诉我哪一组是哪一组,这样我就可以根据它进行分组,然后查看每个总和。不过,我不知道如何获得这一套:

请注意,每次尝试我都从SetB中删除了一个不同的项目。实际上,SetB可能比A大很多项,因此会有更多的项被删除,从而有更多的可能性。一旦我有了上面的内容,我只需要加上计算平方差的字段,然后在尝试时用一个group by进行求和。然后我可以选择最小平方的尝试。我可能需要将中间结果存储在临时表或表变量中,这样我就可以从该ID向后走,以获得成功集合中的元素


因此,问题是:如何生成这些尝试的所有排列?

您可以尝试从setB中提取与setA完全匹配的所有内容,例如20和40,然后将setA中的剩余数字10+30=40相加,并尝试在setB中找到操作数相同的2、10和30的最接近匹配和。 在您的示例中,这将是15+35=50

我不知道你为什么要消除分歧


如果想要两个集合的所有可能组合,可以使用不带ON子句的外部联接。

您没有提到dbms,所以我使用了Oracle

with crossjoined as(
  select b
        ,a
        ,abs(a-b) as diff
        ,row_number() over(partition by b order by abs(a-b), a) as rn
    from SetA cross join SetB
)
,ranked as(
  select b,a,diff, row_number() over(order by diff,a) as rn
    from crossjoined
   where rn = 1
)
select b
  from ranked
 where rn <= (select count(*) from SetA)
 order by b;
第二部分。排列 查询的这一部分基本上为每个B选择最佳的A。这是通过rn=1实现的。每个原始B的结果将有一行。这些行将按差异排序。如果两行具有相同的差异,则将首先对具有最小A的行进行排序。以下是根据您的样本数据进行交叉连接和排名的完整结果:

B    A  DIFF  RN
--   -- ----  --
20   20    0   1
40   40    0   2
15   10    5   3
35   30    5   4
50   40   10   5
第三部分。主查询现在是时候将该集合中的项目删除为集合A中相同数量的项目了。按照查找差异最小的集合的逻辑,我使用排名部分中的排名rn并选择前N行。其中N是A中的项目数


如果我能更详细地解释什么,请告诉我

不确定这是否是一项要求,但这是否确保集合的每个成员只能使用一次?i、 e.如果SetA有10,20,而SetB有9,10,那么您的查询是否返回10,10和10,9-或者它是否返回10,9和20,10?@Martin,它将B和A10配对。因此,我的查询不会每次使用A。是的,我不想让较小的集合变大,而是想让较大的集合变小,以匹配两个集合中最小集合的单位数。这意味着删除项目,而不是复制项目。@AaronLS,我的查询结果包含的行数与最小集的行数相同。但正如马丁所指出的,它可能会多次重复使用相同的A。当我第一次了解平方差时,我也有同样的想法。平方和是确定两组数据的接近程度的概念。然而,它传统上用于将曲线拟合到数据。但基本上这个概念是,如果你有1,12和6,7,那么1和6的差值是5,12和7的差值是5,所以你可以说差值之和是10,但平方和是5025+25。如果你有5,16和6,7,那么差的和也是10,但是平方和要大得多,81=1^2+9^2,因此被认为是更差的拟合。好吧,如果这是企业定义最接近的“拟合”的方式,那么你必须这样做。
Attempt#  Row#   SetA  SetB
1         1       10    15
1         2       20    20 
1         3       30    35
1         4       40    40 
2         1       10    15
2         2       20    20 
2         3       30    35
2         4       40    50 
3         1       10    15
3         2       20    20 
3         3       30    40
3         4       40    50 
etc....
with crossjoined as(
  select b
        ,a
        ,abs(a-b) as diff
        ,row_number() over(partition by b order by abs(a-b), a) as rn
    from SetA cross join SetB
)
,ranked as(
  select b,a,diff, row_number() over(order by diff,a) as rn
    from crossjoined
   where rn = 1
)
select b
  from ranked
 where rn <= (select count(*) from SetA)
 order by b;
B    A  DIFF  RN
--   -- ----  --
15   10 5      1
15   20 5      2
15   30 15     3
15   40 25     4
20   20 0      1
20   10 10     2
20   30 10     3
20   40 20     4
B    A  DIFF  RN
--   -- ----  --
20   20    0   1
40   40    0   2
15   10    5   3
35   30    5   4
50   40   10   5