J'ai un ensemble de données contenant des travailleurs avec leurs informations démographiques comme l'âge, le sexe, l'adresse, etc. et leurs lieux de travail. J'ai créé un RDD à partir de l'ensemble de données et l'ai converti en DataFrame.
Il existe plusieurs entrées pour chaque ID. Par conséquent, j'ai créé un DataFrame qui ne contenait que l'ID du travailleur et les différents bureaux où il/elle avait travaillé.
|----------|----------------|
| **ID** **Office_Loc** |
|----------|----------------|
| 1 |Delhi, Mumbai, |
| | Gandhinagar |
|---------------------------|
| 2 | Delhi, Mandi |
|---------------------------|
| 3 |Hyderbad, Jaipur|
-----------------------------
Je veux calculer la similitude cosinus entre chaque travailleur avec tous les autres travailleurs en fonction de leur emplacement de bureau ".
Donc, j'ai parcouru les lignes du DataFrame, en récupérant une seule ligne du DataFrame:
myIndex = 1
values = (ID_place_df.rdd.zipWithIndex()
.filter(lambda ((l, v), i): i == myIndex)
.map(lambda ((l,v), i): (l, v))
.collect())
puis en utilisant la carte
cos_weight = ID_place_df.select("ID","office_location").rdd\
.map(lambda x: get_cosine(values,x[0],x[1]))
pour calculer la similitude en cosinus entre la ligne extraite et l'ensemble du DataFrame.
Je ne pense pas que mon approche soit bonne puisque j'itère à travers les lignes du DataFrame, cela va à l'encontre du but de l'utilisation de spark. Y a-t-il une meilleure façon de le faire dans pyspark? Veuillez aviser.
Vous pouvez utiliser le package mllib
pour calculer le L2
norme du TF-IDF de chaque ligne. Multipliez ensuite le tableau avec lui-même pour obtenir la similitude cosinus en tant que produit scalaire de deux par deux L2
normes:
1. RDD
rdd = sc.parallelize([[1, "Delhi, Mumbai, Gandhinagar"],[2, " Delhi, Mandi"], [3, "Hyderbad, Jaipur"]])
Calculer TF-IDF
:
documents = rdd.map(lambda l: l[1].replace(" ", "").split(","))
from pyspark.mllib.feature import HashingTF, IDF
hashingTF = HashingTF()
tf = hashingTF.transform(documents)
Vous pouvez spécifier le nombre d'entités dans HashingTF
pour réduire la matrice d'entités (moins de colonnes).
tf.cache()
idf = IDF().fit(tf)
tfidf = idf.transform(tf)
Calculer L2
norme:
from pyspark.mllib.feature import Normalizer
labels = rdd.map(lambda l: l[0])
features = tfidf
normalizer = Normalizer()
data = labels.Zip(normalizer.transform(features))
Calculez la similitude du cosinus en multipliant la matrice par elle-même:
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. ]])
OU: Utilisation d'un produit cartésien et de la fonction dot
sur les tableaux numpy:
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
Comme vous semblez utiliser des cadres de données, vous pouvez utiliser le spark ml
package à la place:
import pyspark.sql.functions as psf
df = rdd.toDF(["ID", "Office_Loc"])\
.withColumn("Office_Loc", psf.split(psf.regexp_replace("Office_Loc", " ", ""), ','))
Calculer 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)
Calculer L2
norme:
from pyspark.ml.feature import Normalizer
normalizer = Normalizer(inputCol="feature", outputCol="norm")
data = normalizer.transform(tfidf)
Produit de matrice de calcul:
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()
OU: en utilisant une jointure et un UDF
pour la fonction 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|
+---+---+-------------------+
Ce didacticiel répertorie différentes méthodes pour multiplier les matrices à grande échelle: https://labs.yodas.com/large-scale-matrix-multiplication-with-pyspark-or-how-to-match-two-large-datasets -of-company-1be4b1b2871e