如何在Neo4j中使用平均函数与集合

6

我想计算两个向量A=[1, 2, 3, 4]和B=[5, 6, 7, 8]的协方差。

协方差(A,B)= Sigma[(ai-AVGa)*(bi-AVGb)] / (n-1)

我的协方差计算问题是:

1)当我写以下代码时,无法嵌套聚合函数:

SUM((ai-avg(a)) * (bi-avg(b)))

2) 或者换个方式,我如何在一个reduce中提取两个集合,例如:

REDUCE(x= 0.0, ai IN COLLECT(a) | bi IN COLLECT(b) | x + (ai-avg(a))*(bi-avg(b)))

3) 如果在oe reduce中无法提取两个集合,当它们分离时如何相关它们的值以计算协方差?

REDUCE(x= 0.0, ai IN COLLECT(a) | x + (ai-avg(a)))
REDUCE(y= 0.0, bi IN COLLECT(b) | y + (bi-avg(b)))

我的意思是我能写嵌套的reduce吗?

4) 有没有使用“unwind”、“extract”等方法的方式

非常感谢您提供的任何帮助。

4个回答

7

cybersam的答案完全没问题,但如果你想避免双重UNWIND导致的n^2笛卡尔积,你可以尝试以下方法:

WITH [1,2,3,4] AS a, [5,6,7,8] AS b
WITH REDUCE(s = 0.0, x IN a | s + x) / SIZE(a) AS e_a,
     REDUCE(s = 0.0, x IN b | s + x) / SIZE(b) AS e_b,
     SIZE(a) AS n, a, b
RETURN REDUCE(s = 0.0, i IN RANGE(0, n - 1) | s + ((a[i] - e_a) * (b[i] - e_b))) / (n - 1) AS cov;

编辑:

不是在指责任何人,但是让我更详细地解释一下为什么你要避免https://dev59.com/NpLea4cB1Zd3GeqP01a2#34423783中的双重UNWIND。就像我下面说的那样,在Cypher中对长度为n的k个集合进行UNWIND操作会导致n^k行结果。所以我们来看两个长度为3的集合,你想计算它们之间的协方差。

> WITH [1,2,3] AS a, [4,5,6] AS b
UNWIND a AS aa
UNWIND b AS bb
RETURN aa, bb;
   | aa | bb
---+----+----
 1 |  1 |  4
 2 |  1 |  5
 3 |  1 |  6
 4 |  2 |  4
 5 |  2 |  5
 6 |  2 |  6
 7 |  3 |  4
 8 |  3 |  5
 9 |  3 |  6

现在我们有n^k = 3^2 = 9行。此时,对这些标识符取平均值意味着我们要对9个值取平均值。
> WITH [1,2,3] AS a, [4,5,6] AS b
UNWIND a AS aa
UNWIND b AS bb
RETURN AVG(aa), AVG(bb);
   | AVG(aa) | AVG(bb)
---+---------+---------
 1 |     2.0 |     5.0

此外,正如我在下面所说的,这不会影响答案,因为重复数字的向量的平均值总是相同的。例如,{1,2,3} 的平均值等于 {1,2,3,1,2,3} 的平均值。对于小的 n 值,这可能无关紧要,但当你开始获取较大的 n 值时,你将开始看到性能下降。
假设你有两个长度为 1000 的向量。使用双倍展开计算每个向量的平均值:
> WITH RANGE(0, 1000) AS a, RANGE(1000, 2000) AS b
UNWIND a AS aa
UNWIND b AS bb
RETURN AVG(aa), AVG(bb);
   | AVG(aa) | AVG(bb)
---+---------+---------
 1 |   500.0 |  1500.0

714毫秒

与使用REDUCE相比明显较慢:

> WITH RANGE(0, 1000) AS a, RANGE(1000, 2000) AS b
RETURN REDUCE(s = 0.0, x IN a | s + x) / SIZE(a) AS e_a,
       REDUCE(s = 0.0, x IN b | s + x) / SIZE(b) AS e_b;
   | e_a   | e_b   
---+-------+--------
 1 | 500.0 | 1500.0

4毫秒

为了将其整合在一起,我将比较两个查询在长度为1000的向量上的完整性:

> WITH RANGE(0, 1000) AS aa, RANGE(1000, 2000) AS bb
UNWIND aa AS a
UNWIND bb AS b
WITH aa, bb, SIZE(aa) AS n, AVG(a) AS avgA, AVG(b) AS avgB
RETURN REDUCE(s = 0, i IN RANGE(0,n-1)| s +((aa[i]-avgA)*(bb[i]-avgB)))/(n-1) AS
 covariance;
   | covariance
---+------------
 1 |    83583.5

9105毫秒

> WITH RANGE(0, 1000) AS a, RANGE(1000, 2000) AS b
WITH REDUCE(s = 0.0, x IN a | s + x) / SIZE(a) AS e_a,
     REDUCE(s = 0.0, x IN b | s + x) / SIZE(b) AS e_b,
          SIZE(a) AS n, a, b
          RETURN REDUCE(s = 0.0, i IN RANGE(0, n - 1) | s + ((a[i] - e_a) * (b[i
] - e_b))) / (n - 1) AS cov;
   | cov    
---+---------
 1 | 83583.5

33 毫秒


谢谢您的回答,您能进一步解释一下为什么我们应该避免使用n^2的笛卡尔积吗? - Mahsa Hassankashi
当您对长度为n的集合进行k次UNWIND操作时,最终会得到n^k行。所以,如果您的k=2向量(或Cypher集合)有1000个值,则双倍的UNWIND操作将使您处理1000^2 = 1,000,000行数据,然后在后续WITH子句中计算这些数据的平均值。尽管这不会影响答案,因为avg(1,2,3,4)=avg(1,2,3,4,1,2,3,4),但您会进行比所需更多的计算。 - Nicole White
非常感谢@Nicole White的描述,我完全理解了,因此在处理大数据时具有巨大的影响! - Mahsa Hassankashi
是的,@MahsaHassankashi,请看我的编辑。如果使用UNWIND,您将会遇到大向量的严重性能问题。 - Nicole White
非常感谢你的详细解释,但我只是想知道为自己而已,如果有一些情况,比如打开一个具有父子关系的JSON集合(没有任何聚合函数的计算,仅用于添加或节点修改) ->因此使用unwind是否有用?因为我听说它有助于提高性能。 - Mahsa Hassankashi
我并不是说永远不要使用UNWIND。我是在说在这种特定情况下,双重UNWIND会导致大向量的问题。@jjaderberg在我之后回答了,我认为他的答案也很好,因为它也避免了n^2扩展。所有这些答案对于小的n都是可以接受的,但是当n增长时,你会开始看到差异,这仍然是我上面描述的原因。 - Nicole White

6
这应该根据您的公式计算协方差,给出样本输入:
WITH [1,2,3,4] AS aa, [5,6,7,8] AS bb
UNWIND aa AS a
UNWIND bb AS b
WITH aa, bb, SIZE(aa) AS n, AVG(a) AS avgA, AVG(b) AS avgB
RETURN REDUCE(s = 0, i IN RANGE(0,n-1)| s +((aa[i]-avgA)*(bb[i]-avgB)))/(n-1) AS covariance;

n较小时,例如原始样本数据时,这种方法是可行的。

然而,正如@NicoleWhite和@jjaderberg指出的那样,当n较大时,这种方法将变得低效。@NicoleWhite提供了一个优雅的通用解决方案。


不错,你比我快了 :) 但我认为你的解开操作会创建一个叉积。 - jjaderberg
@jjaderberg,当我们有嵌套的UNWIND时,“叉积”能否再解释一下? - Mahsa Hassankashi
@MahsaHassankashi 将两个包含四个项目的集合展开,结果会有十六种组合。每个集合中的每个项目都代表了另一个集合中的每个项目。这是一种交叉乘积(有时称为笛卡尔积),通常出现在不经思考的“MATCH”中,比如 MATCH (a:Person), (b:Person),它会给出标签为:Person的节点数的平方。在这种情况下,结果并不重要,因为四个 [5, 6, 7, 8] 集合的平均值与[5, 6, 7, 8]的平均值相同。 - jjaderberg
@jjaderberg 非常感谢,那么我理解,在这些情况下,嵌套的展开对最终结果没有影响,但会影响性能? - Mahsa Hassankashi
是的,但只是偶然。它之所以有效,是因为您正在计算平均值。如果您执行两次展开,然后使用 sum(),则会得到不正确的结果。 - jjaderberg

4
你如何得到集合A和B?avg函数是一种聚合函数,不能在REDUCE上下文中使用,也不能应用于集合。你应该在到达那个点之前计算平均值,但最好的方法取决于你如何获得这两个值集合。如果你已经有单独的结果项,然后收集它们以获得A和B,那就是你可以使用avg的时候。例如:
WITH [1, 2, 3, 4] AS aa UNWIND aa AS a
WITH collect(a) AS aa, avg(a) AS aAvg
RETURN aa, aAvg

对于这两个集合

WITH [1, 2, 3, 4] AS aColl UNWIND aColl AS a
WITH collect(a) AS aColl, avg(a) AS aAvg
WITH aColl, aAvg,[5, 6, 7, 8] AS bColl UNWIND bColl AS b
WITH aColl, aAvg, collect(b) AS bColl, avg(b) AS bAvg
RETURN aColl, aAvg, bColl, bAvg

一旦你得到了两个平均值,我们称之为 aAvgbAvg,以及两个集合,aCollbColl,你可以这样做:

RETURN REDUCE(x = 0.0, i IN range(0, size(aColl) - 1) | x + ((aColl[i] - aAvg) * (bColl[i] - bAvg))) / (size(aColl) - 1) AS covariance

2
我从查询中获取一个集合:MATCH (me)-[:HAS]->(myFavorites)-[x:TAGGED]->(tag)<-[y:TAGGED]-(theirFavorites)<-[:HAS]-(people) WHERE me.name = 'Mahsa' AND people.name='Frank'。实际上,我想要读取“TAGGED”边缘上的属性类型,并在此点产生向量a和b。 - Mahsa Hassankashi

0

非常感谢各位,但我想知道哪种方法最有效

1)在reduce中嵌套展开和范围 -> @cybersam

2)嵌套Reduce -> @Nicole White

3)嵌套With(通过with重置查询) -> @jjaderberg

但是重要的问题是:

为什么你们的计算结果与实际计算结果有误差和差异。

我的意思是,你们的协方差等于= 1.6666666666666667

但在现实世界中,协方差等于= 1.25

请查看:https://www.easycalculation.com/statistics/covariance.php

向量X:[1, 2, 3, 4] 向量Y:[5, 6, 7, 8]

enter image description here

enter image description here

我认为这种差异是因为某些计算没有将(n-1)作为除数考虑进去,而是直接使用了n。因此,当我们将除数从n-1增加到n时,结果会从1.6减少到1.25。

enter image description here


你给出的公式是 Cov(A,B)= Sigma[(ai-AVGa)*(bi-AVGb)] / (n-1),我没有停下来考虑它。当平均值为 2.56.5(这是我们所有答案都给出的值)时,当最后的除数为 n-1 时,结果为 1.666等等,但当最后的除数为 n 时,结果为 1.25 - jjaderberg
协方差为1.67。您可以在R中确认:cov(c(1,2,3,4), c(5,6,7,8)) [1] 1.666667。我不会依赖于那样的在线计算器。 - Nicole White
2
@jjaderberg 是的,我记得由于除数从n-1到n的变化而有所不同。 - Mahsa Hassankashi
我们使用 n - 1 是因为我们正在计算样本协方差。在计算样本统计量时,您需要使用 n - k,其中 k 是您需要计算以得出最终统计量的中间统计量的数量。在这种情况下,您需要在得出最终答案之前计算 k = 1(样本均值)统计量。因此,您的自由度为 n - 1,这是您的分母。https://en.wikipedia.org/wiki/Degrees_of_freedom_(statistics) - Nicole White

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接