如何有效地创建一个新列 DataFrame ,它是其他行的功能 spark ?
DataFrame
spark
这是spark我在这里描述的问题的一种实现:
from nltk.metrics.distance import edit_distance as edit_dist from pyspark.sql.functions import col, udf from pyspark.sql.types import IntegerType d = { 'id': [1, 2, 3, 4, 5, 6], 'word': ['cat', 'hat', 'hag', 'hog', 'dog', 'elephant'] } spark_df = sqlCtx.createDataFrame(pd.DataFrame(d)) words_list = list(spark_df.select('word').collect()) get_n_similar = udf( lambda word: len( [ w for w in words_list if (w['word'] != word) and (edit_dist(w['word'], word) < 2) ] ), IntegerType() ) spark_df.withColumn('n_similar', get_n_similar(col('word'))).show()
输出:
+---+--------+---------+ |id |word |n_similar| +---+--------+---------+ |1 |cat |1 | |2 |hat |2 | |3 |hag |2 | |4 |hog |2 | |5 |dog |1 | |6 |elephant|0 | +---+--------+---------+
这里的问题是我不知道一种方法,不能先将spark当前行与的其他行进行比较,Dataframe而不必先将值收集到中list。有没有一种方法可以应用其他行的泛型函数而无需调用collect?
Dataframe
list
collect
这里的问题是,我不知道一种方法,可以在不首先将值收集到列表中的情况下,告诉spark将当前行与Dataframe中的其他行进行比较。
UDF是不是一种选择,在这里(你不能引用分布DataFrame在udf)你的逻辑的直接翻译是笛卡尔乘积和汇总:
udf
from pyspark.sql.functions import levenshtein, col result = (spark_df.alias("l") .crossJoin(spark_df.alias("r")) .where(levenshtein("l.word", "r.word") < 2) .where(col("l.word") != col("r.word")) .groupBy("l.id", "l.word") .count())
但实际上,您应该尝试做一些更有效的事情:ApacheSpark中的有效字符串匹配
根据问题,您应尝试查找其他近似值以避免完整的笛卡尔积。
如果要保留不匹配的数据,则可以跳过一个过滤器:
(spark_df.alias("l") .crossJoin(spark_df.alias("r")) .where(levenshtein("l.word", "r.word") < 2) .groupBy("l.id", "l.word") .count() .withColumn("count", col("count") - 1))
或(速度较慢,但通用性更高),请参考加入:
(spark_df .select("id", "word") .distinct() .join(result, ["id", "word"], "left") .na.fill(0))