web-dev-qa-db-ja.com

sparkのデータフレーム列の更新

新しいsparkデータフレームAPIを見ると、データフレーム列を変更できるかどうかは不明です。

データフレームの行xyの値を変更するにはどうすればよいですか?

pandasでは、これはdf.ix[x,y] = new_valueになります

編集:以下の説明を統合すると、既存のデータフレームは不変であるため変更できませんが、必要な変更を加えた新しいデータフレームを返すことができます。

np.whereのように、条件に基づいて列の値を単に置き換えたい場合:

from pyspark.sql import functions as F

update_func = (F.when(F.col('update_col') == replace_val, new_value)
                .otherwise(F.col('update_col')))
df = df.withColumn('new_column_name', update_func)

列で何らかの操作を実行し、データフレームに追加される新しい列を作成する場合:

import pyspark.sql.functions as F
import pyspark.sql.types as T

def my_func(col):
    do stuff to column here
    return transformed_value

# if we assume that my_func returns a string
my_udf = F.UserDefinedFunction(my_func, T.StringType())

df = df.withColumn('new_column_name', my_udf('update_col'))

新しい列に古い列と同じ名前を付けたい場合、追加のステップを追加できます。

df = df.drop('update_col').withColumnRenamed('new_column_name', 'update_col')
61
Luke

列をそのように変更することはできませんが、列を操作して、その変更を反映する新しいDataFrameを返すことができます。そのためには、最初に適用する操作を実装するUserDefinedFunctionを作成し、次にその関数をターゲット列のみに選択的に適用します。 Pythonの場合:

from pyspark.sql.functions import UserDefinedFunction
from pyspark.sql.types import StringType

name = 'target_column'
udf = UserDefinedFunction(lambda x: 'new_value', StringType())
new_df = old_df.select(*[udf(column).alias(name) if column == name else column for column in old_df.columns])

new_dfのスキーマはold_dfと同じになりました(old_df.target_columnStringType型であると仮定します)が、列target_columnのすべての値はnew_valueになります。

62
karlson

一般に、列を更新するとき、古い値を新しい値にマップします。 UDFを使用せずにpysparkでこれを行う方法は次のとおりです。

# update df[update_col], mapping old_value --> new_value
from pyspark.sql import functions as F
df = df.withColumn(update_col,
    F.when(df[update_col]==old_value,new_value).
    otherwise(df[update_col])).
35
Paul

DataFramesはRDDに基づいています。 RDDは不変の構造であり、オンサイトで要素を更新することはできません。値を変更するには、SQLに似たDSLまたはmapのようなRDD操作を使用して、元のデータフレームを変換して新しいDataFrameを作成する必要があります。

強く推奨されるスライドデッキ: 大規模データサイエンス向けのSparkでのDataFrameの紹介

13
maasg

maasg が示すように、古いDataFrameに適用されたマップの結果から新しいDataFrameを作成できます。 2つの行がある特定のDataFrame dfの例:

val newDf = sqlContext.createDataFrame(df.map(row => 
  Row(row.getInt(0) + SOMETHING, applySomeDef(row.getAs[Double]("y")), df.schema)

列のタイプが変更された場合、df.schemaの代わりに正しいスキーマを与える必要があることに注意してください。利用可能なメソッドについては、org.Apache.spark.sql.RowのAPIを確認してください: https://spark.Apache.org/docs/latest/api/Java/org/Apache/spark/sql/Row.html

[更新]またはScalaでUDFを使用:

import org.Apache.spark.sql.functions._

val toLong = udf[Long, String] (_.toLong)

val modifiedDf = df.withColumn("modifiedColumnName", toLong(df("columnName"))).drop("columnName")

列名を同じままにする必要がある場合は、名前を元に戻すことができます。

modifiedDf.withColumnRenamed("modifiedColumnName", "columnName")
11
radek1st