web-dev-qa-db-ja.com

どのようにしてSpark DataFrameに新しい列を追加するのですか(PySparkを使って)?

私は(PySpark 1.5.1を使って)Spark DataFrameを持っていて、新しい列を追加したいと思います。

私は何も成功せずに以下を試しました:

type(randomed_hours) # => list

# Create in Python and transform to RDD

new_col = pd.DataFrame(randomed_hours, columns=['new_col'])

spark_new_col = sqlContext.createDataFrame(new_col)

my_df_spark.withColumn("hours", spark_new_col["new_col"])

またこれを使用してエラーを得た:

my_df_spark.withColumn("hours",  sc.parallelize(randomed_hours))

では、どうやってPySparkを使って既存のDataFrameに(Pythonベクトルに基づく)新しい列を追加するのでしょうか。

96
Boris

SparkではDataFrameに任意の列を追加することはできません。新しい列はリテラルを使用しないと作成できません(他のリテラル型は Spark DataFrameに定数列を追加する方法? を参照してください)。

from pyspark.sql.functions import lit

df = sqlContext.createDataFrame(
    [(1, "a", 23.0), (3, "B", -23.0)], ("x1", "x2", "x3"))

df_with_x4 = df.withColumn("x4", lit(0))
df_with_x4.show()

## +---+---+-----+---+
## | x1| x2|   x3| x4|
## +---+---+-----+---+
## |  1|  a| 23.0|  0|
## |  3|  B|-23.0|  0|
## +---+---+-----+---+

既存の列を変換する:

from pyspark.sql.functions import exp

df_with_x5 = df_with_x4.withColumn("x5", exp("x3"))
df_with_x5.show()

## +---+---+-----+---+--------------------+
## | x1| x2|   x3| x4|                  x5|
## +---+---+-----+---+--------------------+
## |  1|  a| 23.0|  0| 9.744803446248903E9|
## |  3|  B|-23.0|  0|1.026187963170189...|
## +---+---+-----+---+--------------------+

joinを使用して含まれています:

from pyspark.sql.functions import exp

lookup = sqlContext.createDataFrame([(1, "foo"), (2, "bar")], ("k", "v"))
df_with_x6 = (df_with_x5
    .join(lookup, col("x1") == col("k"), "leftouter")
    .drop("k")
    .withColumnRenamed("v", "x6"))

## +---+---+-----+---+--------------------+----+
## | x1| x2|   x3| x4|                  x5|  x6|
## +---+---+-----+---+--------------------+----+
## |  1|  a| 23.0|  0| 9.744803446248903E9| foo|
## |  3|  B|-23.0|  0|1.026187963170189...|null|
## +---+---+-----+---+--------------------+----+

または関数/ udfを使って生成します。

from pyspark.sql.functions import Rand

df_with_x7 = df_with_x6.withColumn("x7", Rand())
df_with_x7.show()

## +---+---+-----+---+--------------------+----+-------------------+
## | x1| x2|   x3| x4|                  x5|  x6|                 x7|
## +---+---+-----+---+--------------------+----+-------------------+
## |  1|  a| 23.0|  0| 9.744803446248903E9| foo|0.41930610446846617|
## |  3|  B|-23.0|  0|1.026187963170189...|null|0.37801881545497873|
## +---+---+-----+---+--------------------+----+-------------------+

Catalyst式にマップされるパフォーマンス的な組み込み関数(pyspark.sql.functions)は、通常、Pythonユーザー定義関数よりも優先されます。

任意のRDDの内容を列として追加したい場合は、

  • 既存のデータフレームに 行番号を追加する
  • rDDでzipWithIndexを呼び出してデータフレームに変換します。
  • 結合キーとしてインデックスを使用して両方を結合する
155
zero323

UDFを使用して列を追加するには

df = sqlContext.createDataFrame(
    [(1, "a", 23.0), (3, "B", -23.0)], ("x1", "x2", "x3"))

from pyspark.sql.functions import udf
from pyspark.sql.types import *

def valueToCategory(value):
   if   value == 1: return 'cat1'
   Elif value == 2: return 'cat2'
   ...
   else: return 'n/a'

# NOTE: it seems that calls to udf() must be after SparkContext() is called
udfValueToCategory = udf(valueToCategory, StringType())
df_with_cat = df.withColumn("category", udfValueToCategory("x1"))
df_with_cat.show()

## +---+---+-----+---------+
## | x1| x2|   x3| category|
## +---+---+-----+---------+
## |  1|  a| 23.0|     cat1|
## |  3|  B|-23.0|      n/a|
## +---+---+-----+---------+
50
Mark Rajcok

Spark 2.0の場合

# assumes schema has 'age' column 
df.select('*', (df.age + 10).alias('agePlusTen'))
25
Luke W

私は非常によく似たユースケースのための一般化された例を提供したいです。

ユースケース:私はから成るcsvを持っています:

First|Third|Fifth
data|data|data
data|data|data
...billion more lines

私はいくつかの変換を実行する必要があり、最後のcsvは次のようになる必要があります。

First|Second|Third|Fourth|Fifth
data|null|data|null|data
data|null|data|null|data
...billion more lines

これはいくつかのモデルで定義されているスキーマであり、最終的なデータがSQL Bulk Insertsなどと相互運用可能である必要があるため、これを行う必要があります。

そう:

1)spark.readを使って元のcsvを読み、それを "df"と呼びます。

2)データに何かをします。

3)このスクリプトを使用してnull列を追加します。

outcols = []
for column in MY_COLUMN_LIST:
    if column in df.columns:
        outcols.append(column)
    else:
        outcols.append(lit(None).cast(StringType()).alias('{0}'.format(column)))

df = df.select(outcols)

このようにして、csvをロードした後にスキーマを構造化することができます(多くのテーブルでこれを行わなければならない場合、列の並べ替えにも使用できます)。

0
bloodrootfc

以下の手順でDataFrameに直接列を追加できます。

from pyspark.sql.functions import when
df = spark.createDataFrame([["amit", 30], ["rohit", 45], ["sameer", 50]], ["name", "age"])
df = df.withColumn("profile", when(df.age >= 40, "Senior").otherwise("Executive"))
df.show()
0
yogesh

列を追加する最も簡単な方法は "withColumn"を使うことです。データフレームはsqlContextを使用して作成されるので、スキーマを指定する必要があります。そうしないと、デフォルトでデータセットで使用可能になります。スキーマが指定されていると、毎回変更するときにワークロードが面倒になります。

以下は検討できる例です。

from pyspark.sql import SQLContext
from pyspark.sql.types import *
sqlContext = SQLContext(sc) # SparkContext will be sc by default 

# Read the dataset of your choice (Already loaded with schema)
Data = sqlContext.read.csv("/path", header = True/False, schema = "infer", sep = "delimiter")

# For instance the data has 30 columns from col1, col2, ... col30. If you want to add a 31st column, you can do so by the following:
Data = Data.withColumn("col31", "Code goes here")

# Check the change 
Data.printSchema()