Apache spark Spark中单数据帧的局部敏感散列
我已经阅读了有关位置敏感哈希的Spark部分,但仍然不了解其中的一些内容: https://spark.apache.org/docs/latest/ml-features.htmllocality-sensitive-hashing 还有两个数据帧的弯曲随机投影示例。我有一个简单的点空间数据集,如: 当然,稍后我将有数百万个点,DataFrame看起来像: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
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。我还没有测试过它,但应该可以。