(user, product, review)
のデータセットがあり、mllibのALSアルゴリズムにフィードしたい。
アルゴリズムはユーザーと製品が数字である必要がありますが、私のものは文字列のユーザー名と文字列のSKUです。
今は、個別のユーザーとSKUを取得し、Sparkの外部でそれらに数値IDを割り当てています。
これを行うより良い方法があるかどうか疑問に思っていました。私が考えたアプローチの1つは、1〜n
を本質的に列挙するカスタムRDDを作成し、2つのRDDでZipを呼び出すことです。
Spark 1.から始めて、これを簡単に解決するために使用できる2つの方法があります。
RDD.zipWithIndex
はSeq.zipWithIndex
、連続した(Long
)番号を追加します。これは、各パーティションの要素を最初にカウントする必要があるため、入力は2回評価されます。これを使用する場合は、入力RDDをキャッシュします。RDD.zipWithUniqueId
は、一意のLong
IDも提供しますが、連続していることは保証されません。 (各パーティションの要素数が同じ場合にのみ連続します。)利点は、入力について何も知る必要がないため、二重評価が発生しないことです。同様の使用例では、文字列値をハッシュしました。 http://blog.cloudera.com/blog/2014/03/why-Apache-spark-is-a-crossover-hit-for-data-scientists/ を参照してください
def nnHash(tag: String) = tag.hashCode & 0x7FFFFF
var tagHashes = postIDTags.map(_._2).distinct.map(tag =>(nnHash(tag),tag))
あなたはすでにこのようなことをしているように聞こえますが、ハッシュは管理しやすいかもしれません。
Mateiは、ここで、RDDでzipWithIndex
をエミュレートするアプローチを提案しました。これは、各パーティション内でグローバルに一意になるIDを割り当てることになります。 https://groups.google.com/forum/# !topic/spark-users/WxXvcn2gl1E
別の簡単なオプションは、DataFramesを使用しており、一意性のみを懸念している場合、関数 MonotonicallyIncreasingID を使用することです。
import org.Apache.spark.sql.functions.monotonicallyIncreasingId
val newDf = df.withColumn("uniqueIdColumn", monotonicallyIncreasingId)
編集:MonotonicallyIncreasingID
は廃止され、削除されました since Spark 2. ;現在はmonotonically_increasing_id
。
すでに monotonically_increasing_id() を推奨しており、IntsではなくLongsを作成する問題に言及しています。
ただし、私の経験では(注意-Spark 1.6)-単一のエグゼキューターで使用する場合(前の1へのパーティション分割)、エグゼキュータープレフィックスは使用されず、数値を安全にキャストできます)明らかに、Integer.MAX_VALUE未満の行が必要です。
monotonically_increasing_id()が表示されますが答えになりますが、残念ながらALSでは64ビットの数値を生成し、 ALSは32ビットのものを想定しています(deekについてはradek1stの回答を参照してください)。
私が見つけた解決策は、 zipWithIndex() を使用することです。これは、Darabosの回答に記載されています。実装方法は次のとおりです。
userids
と呼ばれる個別のユーザーを持つ単一列のDataFrameが既にある場合は、次のようにルックアップテーブル(LUT)を作成できます。
# PySpark code
user_als_id_LUT = sqlContext.createDataFrame(userids.rdd.map(lambda x: x[0]).zipWithIndex(), StructType([StructField("userid", StringType(), True),StructField("user_als_id", IntegerType(), True)]))
次のことができます。
もちろん、アイテムにも同じことを行います。