年齢、性別、住所などの人口統計情報と労働者の勤務地を含むデータセットがあります。データセットからRDDを作成し、DataFrameに変換しました。
各IDには複数のエントリがあります。そのため、私は、DataFrameを作成しました。これには、ワーカーのIDと、ワーカーが働いていたさまざまなオフィスの場所だけが含まれています。
|----------|----------------|
| **ID** **Office_Loc** |
|----------|----------------|
| 1 |Delhi, Mumbai, |
| | Gandhinagar |
|---------------------------|
| 2 | Delhi, Mandi |
|---------------------------|
| 3 |Hyderbad, Jaipur|
-----------------------------
オフィスの場所に基づいて、各ワーカーと他のすべてのワーカー間のコサイン類似度を計算したいと思います。
そこで、DataFrameの行を繰り返し処理して、DataFrameから単一の行を取得しました。
myIndex = 1
values = (ID_place_df.rdd.zipWithIndex()
.filter(lambda ((l, v), i): i == myIndex)
.map(lambda ((l,v), i): (l, v))
.collect())
そしてマップを使用して
cos_weight = ID_place_df.select("ID","office_location").rdd\
.map(lambda x: get_cosine(values,x[0],x[1]))
抽出された行とDataFrame全体の間のコサイン類似度を計算します。
私はDataFrameの行を繰り返し処理しているため、私のアプローチは良いものだとは思いません。それは、sparkを使用する目的全体を無効にします。 pysparkでそれを行うより良い方法はありますか?親切なアドバイス。
mllib
パッケージを使用して、すべての行のTF-IDFのL2
ノルムを計算できます。次に、テーブルとそれ自体を乗算して、2の2のドット積としてのコサイン類似度を取得しますL2
norms:
1。 RDD
rdd = sc.parallelize([[1, "Delhi, Mumbai, Gandhinagar"],[2, " Delhi, Mandi"], [3, "Hyderbad, Jaipur"]])
計算TF-IDF
:
documents = rdd.map(lambda l: l[1].replace(" ", "").split(","))
from pyspark.mllib.feature import HashingTF, IDF
hashingTF = HashingTF()
tf = hashingTF.transform(documents)
HashingTF
で特徴の数を指定して、特徴行列を小さくする(列を減らす)ことができます。
tf.cache()
idf = IDF().fit(tf)
tfidf = idf.transform(tf)
L2
normを計算:
from pyspark.mllib.feature import Normalizer
labels = rdd.map(lambda l: l[0])
features = tfidf
normalizer = Normalizer()
data = labels.Zip(normalizer.transform(features))
行列にそれ自体を乗算してコサイン類似度を計算します。
from pyspark.mllib.linalg.distributed import IndexedRowMatrix
mat = IndexedRowMatrix(data).toBlockMatrix()
dot = mat.multiply(mat.transpose())
dot.toLocalMatrix().toArray()
array([[ 0. , 0. , 0. , 0. ],
[ 0. , 1. , 0.10794634, 0. ],
[ 0. , 0.10794634, 1. , 0. ],
[ 0. , 0. , 0. , 1. ]])
OR:デカルト積とnumpy配列での関数dot
の使用:
data.cartesian(data)\
.map(lambda l: ((l[0][0], l[1][0]), l[0][1].dot(l[1][1])))\
.sortByKey()\
.collect()
[((1, 1), 1.0),
((1, 2), 0.10794633570596117),
((1, 3), 0.0),
((2, 1), 0.10794633570596117),
((2, 2), 1.0),
((2, 3), 0.0),
((3, 1), 0.0),
((3, 2), 0.0),
((3, 3), 1.0)]
2。 DataFrame
データフレームを使用しているようなので、代わりにspark ml
packageを使用できます。
import pyspark.sql.functions as psf
df = rdd.toDF(["ID", "Office_Loc"])\
.withColumn("Office_Loc", psf.split(psf.regexp_replace("Office_Loc", " ", ""), ','))
TF-IDFを計算します。
from pyspark.ml.feature import HashingTF, IDF
hashingTF = HashingTF(inputCol="Office_Loc", outputCol="tf")
tf = hashingTF.transform(df)
idf = IDF(inputCol="tf", outputCol="feature").fit(tf)
tfidf = idf.transform(tf)
L2
ノルムを計算:
from pyspark.ml.feature import Normalizer
normalizer = Normalizer(inputCol="feature", outputCol="norm")
data = normalizer.transform(tfidf)
行列の積を計算します。
from pyspark.mllib.linalg.distributed import IndexedRow, IndexedRowMatrix
mat = IndexedRowMatrix(
data.select("ID", "norm")\
.rdd.map(lambda row: IndexedRow(row.ID, row.norm.toArray()))).toBlockMatrix()
dot = mat.multiply(mat.transpose())
dot.toLocalMatrix().toArray()
OR:関数UDF
に結合とdot
を使用:
dot_udf = psf.udf(lambda x,y: float(x.dot(y)), DoubleType())
data.alias("i").join(data.alias("j"), psf.col("i.ID") < psf.col("j.ID"))\
.select(
psf.col("i.ID").alias("i"),
psf.col("j.ID").alias("j"),
dot_udf("i.norm", "j.norm").alias("dot"))\
.sort("i", "j")\
.show()
+---+---+-------------------+
| i| j| dot|
+---+---+-------------------+
| 1| 2|0.10794633570596117|
| 1| 3| 0.0|
| 2| 3| 0.0|
+---+---+-------------------+
このチュートリアルでは、大規模な行列を乗算するためのさまざまな方法を示します: large-datasets-of-company-1be4b1b2871e