2017-09-21 29 views
0

私は9ミルの行と80 Kの列を持つ行列Aを持っています。行列自体は非常にまばらです。今、私は比pyspark大行列操作

ratio = (A.T x A)/(n-((1-A).T x (1-A))) 

は映画のいずれかのように見える(M1またはM2)、それらの割合は何している列が、私は人々のために計算したいユーザーは私の行や映画です想像して取得したいです両方の映画(m1とm2)のように見える。

私は、Aをrddに変換することによって、最初の部分(A.T x A)の解を見つけました。

def coordinateMatrixMultiply(leftmatrix, rightmatrix): 
     left = leftmatrix.map(lambda (i, j, v): (j, (i, v))) 
     right = rightmatrix.map(lambda (j, k, w): (j, (k, w))) 
     productEntries = left \ 
         .join(right) \ 
         .map(lambda (x, ((i, v), (k, w))): ((i, k), (v * w))) \ 
         .reduceByKey(lambda x,y: x+y) \ 
         .map(lambda ((i, k), sum): (i, k, sum)) 
     return productEntries 

しかし、私は(1-A).T X(1-A)のためのサイズで解決することがはるかに困難である分母を見つけます。メモリのため、単純に不可能であるものの密度の高い行列を作成しようとします。私はまた、多数のデータフレームを結合するために共用体をすべて使用しようとしましたが、それは非常に遅いです。これを行うより良い方法はありますか?ありがとう!

+0

だけの思考 - かなり密行列を維持するよりは、なぜCRません'user_id'と' movie_id'の2つのカラムを持つデータセットを作成します。それからあなたはSELF JOINであなたが望むものを達成できると信じていますか? – arun

+0

ええ、それは私がやったことです。しかし、dataframe/rddはまばらです。 'または'の部分を得るために、私は1-A部分を取得する必要があります。あなたはその部分をどうやって手に入れようとしますか?ありがとう! – vortex

+0

なぜ行列計算にnumpyを使用しないのですか? –

答えて

0

あなたはこのタイプの計算を行うために行列積を必要としません:

まず者は、0と1のサンプルデータフレームを作成してみましょう:

import numpy as np 
import pyspark.sql.funtions as psf 
from pyspark.sql import Window 

df = spark.createDataFrame(
    sc.parallelize([["id" + str(n)] + np.random.randint(0, 2, 10).tolist() for n in range(100)]), 
    ["id"] + ["movie" + str(i) for i in range(10)]) 
df.show() 

    +----+------+------+------+------+------+------+------+------+------+------+ 
    | id|movie0|movie1|movie2|movie3|movie4|movie5|movie6|movie7|movie8|movie9| 
    +----+------+------+------+------+------+------+------+------+------+------+ 
    | id0|  1|  0|  1|  1|  1|  0|  0|  0|  0|  1| 
    | id1|  0|  1|  1|  0|  0|  0|  1|  0|  1|  0| 
    | id2|  1|  1|  1|  0|  0|  1|  1|  0|  0|  1| 
    | id3|  1|  0|  0|  1|  0|  1|  0|  0|  0|  1| 
    | id4|  0|  0|  0|  1|  1|  0|  0|  1|  0|  1| 
    | id5|  1|  1|  1|  0|  1|  0|  0|  0|  1|  0| 
    | id6|  0|  1|  1|  0|  1|  0|  0|  1|  0|  1| 
    | id7|  1|  1|  1|  1|  0|  1|  1|  0|  1|  0| 
    | id8|  0|  1|  0|  0|  1|  1|  1|  0|  1|  1| 
    | id9|  1|  0|  1|  0|  0|  1|  1|  0|  1|  0| 
    |id10|  1|  0|  1|  1|  0|  1|  0|  1|  0|  0| 
    |id11|  1|  0|  0|  0|  0|  0|  1|  1|  0|  0| 
    |id12|  0|  1|  0|  0|  1|  1|  1|  0|  1|  0| 
    |id13|  0|  0|  1|  1|  1|  1|  0|  0|  0|  1| 
    |id14|  1|  0|  0|  0|  0|  1|  0|  1|  0|  0| 
    |id15|  1|  1|  0|  1|  0|  0|  0|  0|  0|  0| 
    |id16|  1|  0|  1|  1|  0|  1|  1|  0|  1|  0| 
    |id17|  1|  0|  1|  0|  0|  1|  0|  0|  1|  0| 
    |id18|  1|  0|  1|  1|  1|  1|  0|  0|  0|  0| 
    |id19|  0|  1|  1|  0|  0|  1|  0|  0|  1|  0| 
    +----+------+------+------+------+------+------+------+------+------+------+ 

最初のステップは、映画の列を爆発することです各movieワットについて

df_expl = df\ 
    .select(
     "id", 
     psf.explode(
      psf.array(
       [psf.when(df[c] == 1, psf.lit(c)).otherwise(None) for c in df.columns if c != "id"] 
      )).alias("movie"))\ 
    .filter("movie IS NOT NULL") 

:私たちは、唯一の2列、id用とmovieための1つを持っていますe'll window機能を使用して、それを見ている人の数を計算:

w = Window.partitionBy("movie") 
df_count = df_expl.withColumn("count", psf.count("*").over(w)) 

を現在の映画のペアを取得するには、それ自体で、このデータフレームを参加します:

df1 = df_count.select([df_count[c].alias(c + "1") for c in df_count.columns]) 
df2 = df_count.select([df_count[c].alias(c + "2") for c in df_count.columns]) 

df12 = df1.join(df2, (df1.id1 == df2.id2) & (df1.movie1 < df2.movie2)).drop("id2") 

そして最後に、それぞれの(movie1, movie2)ペア、我々はどちらか見てきた人々の間の両方を見ている人の割合を計算します:

res = df12\ 
    .groupBy("movie1", "movie2")\ 
    .agg(
     psf.count("id1").alias("count12"), 
     psf.max("count1").alias("count1"), 
     psf.max("count2").alias("count2"))\ 
    .withColumn("pct", psf.col("count12")/(psf.col("count1") + psf.col("count2") - psf.col("count12"))) 
res.sort("movie1", "movie2").show() 

    +------+------+-------+------+------+-------------------+ 
    |movie1|movie2|count12|count1|count2|    pct| 
    +------+------+-------+------+------+-------------------+ 
    |movie0|movie1|  20| 43| 48|0.28169014084507044| 
    |movie0|movie2|  24| 43| 50|0.34782608695652173| 
    |movie0|movie3|  27| 43| 52|0.39705882352941174| 
    |movie0|movie4|  17| 43| 47| 0.2328767123287671| 
    |movie0|movie5|  18| 43| 46| 0.2535211267605634| 
    |movie0|movie6|  20| 43| 44|0.29850746268656714| 
    |movie0|movie7|  13| 43| 35|    0.2| 
    |movie0|movie8|  20| 43| 44|0.29850746268656714| 
    |movie0|movie9|  15| 43| 47|    0.2| 
    |movie1|movie2|  26| 48| 50| 0.3611111111111111| 
    |movie1|movie3|  25| 48| 52| 0.3333333333333333| 
    |movie1|movie4|  27| 48| 47|0.39705882352941174| 
    |movie1|movie5|  23| 48| 46| 0.323943661971831| 
    |movie1|movie6|  25| 48| 44| 0.373134328358209| 
    |movie1|movie7|  17| 48| 35|0.25757575757575757| 
    |movie1|movie8|  24| 48| 44|0.35294117647058826| 
    |movie1|movie9|  21| 48| 47|0.28378378378378377| 
    |movie2|movie3|  25| 50| 52| 0.3246753246753247| 
    |movie2|movie4|  28| 50| 47| 0.4057971014492754| 
    |movie2|movie5|  27| 50| 46| 0.391304347826087| 
    +------+------+-------+------+------+-------------------+