我正在尝试在Spark中执行卡方测试,但是我什么都没得到。我有一个相当大的数据集(〜5 TB),所以我确实需要使用Spark来执行此操作-否则,我将使用Pandas或手动对其进行编码。另外,一列中不同值的数量最多可以达到10 ^ 5,因此我无法使用便捷的交叉表方法来计算列联矩阵。
数据存储在DataFrame中。大约有20列,但是很明显,卡方检验一次只需要两列。我们将它们称为A列和B列。我尝试使用交叉表方法构建列联矩阵。只要每列中的不重复值的数量小于10 ^ 4,就可以很好地工作,但是我的某些列中的不重复值都超过10 ^ 5。
我还尝试增加对不同值的数量的限制。几个相关的问题引用了spark.sql.pivotmaxvalues,默认情况下将其设置为10 ^ 4。我尝试了spark.conf.set('spark.sql.pivotmaxvalues',100000),但这没有帮助。
到目前为止,我最好的方法是获取A的计数,B的计数,(A,B)的计数并从那里组合结果。这非常有效,因为相异对(A,B)的数量相当容易处理(这意味着列联矩阵稀疏)。我还必须返回并从所有未出现在数据集中的(A,B)对中计算期望值。第二部分需要更长的时间。
这是我到目前为止所取得的最好成绩。假设数据位于具有nRows行的DataFrame df中,并且用于测试的列为A和B。
countA = df.groupBy('A').count()
countA = countA.withColumnRenamed('count', 'NA')
countB = df.groupBy('B').count()
countB = countB.withColumnRenamed('count', 'NB')
countAB = df.groupBy('A', 'B').count()
countAB = countAB.withColumnRenamed('count', 'NAB')
countAB = countAB.join(countA, 'A').join(countB, 'B')
countAB = countAB.withColumn('Expected', countAB['NA'] * countAB['NB'] / nRows)
countAB = countAB.withColumn('Chi2', (countAB['Expected'] - countAB['NAB'])**2 / countAB['Expected'])
missing = countA.crossJoin(countB).join(countAB, ['A', 'B'], 'left_anti')
missing = missing.withColumn('Chi2', missing['NA'] * missing['NB'] / nRows)
total1 = countAB.groupBy().sum('Chi2')
total2 = missing.groupBy().sum('Chi2')
如果我尝试使用交叉表方法,则会出现以下错误:
IllegalArgumentException:“要求失败:A的不同值的数量不能超过1e4。当前为15387”