Apache spark Spark中单数据帧的局部敏感散列

Apache spark Spark中单数据帧的局部敏感散列,apache-spark,pyspark,apache-spark-mllib,Apache Spark,Pyspark,Apache Spark Mllib,我已经阅读了有关位置敏感哈希的Spark部分,但仍然不了解其中的一些内容: https://spark.apache.org/docs/latest/ml-features.htmllocality-sensitive-hashing 还有两个数据帧的弯曲随机投影示例。我有一个简单的点空间数据集,如: 当然,稍后我将有数百万个点,DataFrame看起来像: X Y id 1 11.6133 48.1075 2 11.6142 4

我已经阅读了有关位置敏感哈希的Spark部分,但仍然不了解其中的一些内容:

https://spark.apache.org/docs/latest/ml-features.htmllocality-sensitive-hashing

还有两个数据帧的弯曲随机投影示例。我有一个简单的点空间数据集,如:

当然,稍后我将有数百万个点,DataFrame看起来像:

  X        Y
id                  
1   11.6133  48.1075
2   11.6142  48.1066
3   11.6108  48.1061
4   11.6207  48.1192
5   11.6221  48.1223
6   11.5969  48.1276
7   11.5995  48.1258
8   11.6127  48.1066
9   11.6430  48.1275
10  11.6368  48.1278
11  11.5930  48.1156
我的问题是:如何将彼此接近的点放在相同的组中,这样我的原始数据帧将有一个包含此哈希/组的附加列

最好的, Marcin

雄鹿计划正是你所需要的。每个点的结果哈希可以是一个组值。唯一的问题是选择合适的半径,这将设置每个铲斗的大小。使用.setBucketLength0.02设置半径。另一个小问题是将散列从向量提取到列。我使用这种方法:

以您的数据为例

import org.apache.spark.ml.feature.BucketedRandomProjectionLSH
import org.apache.spark.ml.linalg.Vectors
import org.apache.spark.ml.linalg.Vector

val dfA = spark.createDataFrame(Seq(
  (1, Vectors.dense(11.6133, 48.1075)),
  (2, Vectors.dense(11.6142, 48.1066)),
  (3, Vectors.dense(11.6108, 48.1061)),
  (4, Vectors.dense(11.6207, 48.1192)),
  (5, Vectors.dense(11.6221, 48.1223)),
  (6, Vectors.dense(11.5969, 48.1276)),
  (7, Vectors.dense(11.5995, 48.1258)),
  (8, Vectors.dense(11.6127, 48.1066)),
  (9, Vectors.dense(11.6430, 48.1275)),
  (10, Vectors.dense(11.6368, 48.1278)),
  (11, Vectors.dense(11.5930, 48.1156))
  )).toDF("id", "coord")

val brp = new BucketedRandomProjectionLSH()
  .setBucketLength(0.02)
  .setNumHashTables(1)
  .setInputCol("coord")
  .setOutputCol("hashes")
val model = brp.fit(dfA)

val res = model.transform(dfA)

val vecToSeq = udf((v: Vector) => v.toArray).asNondeterministic

res.select ($"id", vecToSeq($"hashes"(0))(0) as "bucket").show
输出为半径为0.02的两组:

  +---+------+
  | id|bucket|
  +---+------+
  |  1|2473.0|
  |  2|2473.0|
  |  3|2473.0|
  |  4|2474.0|
  |  5|2474.0|
  |  6|2474.0|
  |  7|2474.0|
  |  8|2473.0|
  |  9|2474.0|
  | 10|2474.0|
  | 11|2473.0|

下面是一段执行LSH的scala代码。基本上,lsh需要一个可以用VectorAssembler构建的组合向量

//构建数据帧 val数据=11.6133 48.1075 2 11.6142 48.1066 3 11.6108 48.1061 4 11.6207 48.1192 5 11.6221 48.1223 6 11.5969 48.1276 7 11.5995 48.1258 8 11.6127 48.1066 9 11.6430 48.1275 10 11.6368 48.1278 11 11.5930 48.1156 val df=数据 .split\\s*\\n\\s* .map\u.split\\s+匹配{ 案例a,b,c=>a.toInt,b.toDouble,c.toDouble } 托塞克先生 .托菲德,X,Y val汇编程序=新矢量汇编程序 .setInputColsArrayX,Y .setOutputColv val df2=assembler.transformdf val lsh=新BucketedrandomprojectionSH .setInputColv .setBucketLength1e-3//根据您的用例更改它 .setOutputCollsh val结果=lsh.fitdf2.transformdf2.orderBylsh //lsh位于向量数组中。要提取double,我们可以使用 //数组的getItem和向量的UDF。 val extract=udfvector:org.apache.spark.ml.linalg.Vector=>vector0 result.withColumnlsh,extractcollsh.getItem0.showfalse
很好,我明天会测试它,27432744桶中的数字是如何创建的,为什么不是1,2?请参阅算法文档:。由于散列是相同的,所以整个空间被划分为多个组和多个带。你的分数在这两个波段。最好使用两个哈希来获得多边形的平行六面体或更多。我正在尝试将您的代码重写为PySpark,我对最后两行代码有问题,您能帮忙吗?您和@Oli的解决方案都很好,谢谢您的帮助!半径->的问题。收进长度0.02这是弧度,公里还是什么?我已经阅读了说明书,但对meGreat来说还不清楚,我明天会测试它并给出反馈!它可以工作,即使我能够毫无问题地将其重写为PySpark,但有一个问题:当我将数据写入csv时,lsh列的编写方式类似于[DenseVector[21188.0].如何从中仅获取21188?我编辑了我的答案,用一种从向量数组中提取值的方法。很好!也许你知道如何将其重写为PySpark?我正在尝试使用lambda函数,但获取'DenseVector'对象不可调用try extract=F.udflambda v:v[0]还有result.withColumnlsh,extractF.col'lsh.getItem0。我还没有测试过它,但应该可以。