web-dev-qa-db-ja.com

pysparkのデータフレームのすべての行間のコサイン類似度の計算

年齢、性別、住所などの人口統計情報と労働者の勤務地を含むデータセットがあります。データセットから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でそれを行うより良い方法はありますか?親切なアドバイス。

8

mllibパッケージを使用して、すべての行のTF-IDFのL2ノルムを計算できます。次に、テーブルとそれ自体を乗算して、2の2のドット積としてのコサイン類似度を取得しますL2norms:

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)
  • L2normを計算:

    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 mlpackageを使用できます。

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

19
MaFF