df
という名前のVectorUDT
列を持つデータフレームfeatures
があります。列の要素、たとえば最初の要素を取得するにはどうすればよいですか?
私は以下をやってみました
_from pyspark.sql.functions import udf
first_elem_udf = udf(lambda row: row.values[0])
df.select(first_elem_udf(df.features)).show()
_
しかし、net.razorvine.pickle.PickleException: expected zero arguments for construction of ClassDict(for numpy.dtype)
エラーが発生します。代わりにfirst_elem_udf = first_elem_udf(lambda row: row.toArray()[0])
を実行しても同じエラーが発生します。
explode()
も試しましたが、配列またはマップタイプが必要なため、エラーが発生します。
これはよくある操作だと思います。
出力をfloat
に変換します。
from pyspark.sql.types import DoubleType
from pyspark.sql.functions import lit, udf
def ith_(v, i):
try:
return float(v[i])
except ValueError:
return None
ith = udf(ith_, DoubleType())
使用例:
from pyspark.ml.linalg import Vectors
df = sc.parallelize([
(1, Vectors.dense([1, 2, 3])),
(2, Vectors.sparse(3, [1], [9]))
]).toDF(["id", "features"])
df.select(ith("features", lit(1))).show()
## +-----------------+
## |ith_(features, 1)|
## +-----------------+
## | 2.0|
## | 9.0|
## +-----------------+
説明:
出力値は同等のJavaオブジェクトに再シリアル化する必要があります。values
にアクセスしたい場合(SparseVectors
に注意)、item
を使用する必要があります方法:
v.values.item(0)
これは、標準のPythonスカラーを返します。同様に、すべての値に密な構造としてアクセスする場合は、次のようにします。
v.toArray().tolist()
Spark.sqlを使用する場合は、次のカスタム関数 'to_array'を使用して、ベクターを任意の配列に変換できます。その後、配列として操作できます。
from pyspark.sql.types import ArrayType, DoubleType
def to_array_(v):
return v.toArray().tolist()
from pyspark.sql import SQLContext
sqlContext=SQLContext(spark.sparkContext, sparkSession=spark, jsqlContext=None)
sqlContext.udf.register("to_array",to_array_, ArrayType(DoubleType()))
from pyspark.ml.linalg import Vectors
df = sc.parallelize([
(1, Vectors.dense([1, 2, 3])),
(2, Vectors.sparse(3, [1], [9]))
]).toDF(["id", "features"])
df.createOrReplaceTempView("tb")
spark.sql("""select * , to_array(features)[1] Second from tb """).toPandas()
id features Second
0 1 [1.0, 2.0, 3.0] 2.0
1 2 (0.0, 9.0, 0.0) 9.0
Explode()を使用できないという同じ問題に遭遇しました。できることの1つは、pyspark.ml.featureライブラリの VectorSlice を使用することです。そのようです:
from pyspark.ml.feature import VectorSlicer
from pyspark.ml.linalg import Vectors
from pyspark.sql.types import Row
slicer = VectorSlicer(inputCol="features", outputCol="features_one", indices=[0])
output = slicer.transform(df)
output.select("features", "features_one").show()