Wie füge ich eine Spark-Spalte in einen Spark DataFrame ein?


137

Ich möchte eine Spalte in a DataFramemit einem beliebigen Wert hinzufügen (das ist für jede Zeile gleich). Ich erhalte eine Fehlermeldung, wenn ich withColumnFolgendes verwende:

dt.withColumn('new_column', 10).head(5)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-50-a6d0257ca2be> in <module>()
      1 dt = (messages
      2     .select(messages.fromuserid, messages.messagetype, floor(messages.datetime/(1000*60*5)).alias("dt")))
----> 3 dt.withColumn('new_column', 10).head(5)

/Users/evanzamir/spark-1.4.1/python/pyspark/sql/dataframe.pyc in withColumn(self, colName, col)
   1166         [Row(age=2, name=u'Alice', age2=4), Row(age=5, name=u'Bob', age2=7)]
   1167         """
-> 1168         return self.select('*', col.alias(colName))
   1169 
   1170     @ignore_unicode_prefix

AttributeError: 'int' object has no attribute 'alias'

Es scheint, dass ich die Funktion dazu bringen kann, so zu arbeiten, wie ich möchte, indem ich eine der anderen Spalten addiere und subtrahiere (so dass sie zu Null addieren) und dann die gewünschte Zahl addiere (in diesem Fall 10):

dt.withColumn('new_column', dt.messagetype - dt.messagetype + 10).head(5)
[Row(fromuserid=425, messagetype=1, dt=4809600.0, new_column=10),
 Row(fromuserid=47019141, messagetype=1, dt=4809600.0, new_column=10),
 Row(fromuserid=49746356, messagetype=1, dt=4809600.0, new_column=10),
 Row(fromuserid=93506471, messagetype=1, dt=4809600.0, new_column=10),
 Row(fromuserid=80488242, messagetype=1, dt=4809600.0, new_column=10)]

Das ist höchst hacky, oder? Ich nehme an, es gibt einen legitimeren Weg, dies zu tun?

Antworten:


219

Spark 2.2+

Spark 2.2 führt typedLitin die Unterstützung ein Seq, Mapund Tuples( SPARK-19254 ) und folgende Aufrufe sollten unterstützt werden (Scala):

import org.apache.spark.sql.functions.typedLit

df.withColumn("some_array", typedLit(Seq(1, 2, 3)))
df.withColumn("some_struct", typedLit(("foo", 1, 0.3)))
df.withColumn("some_map", typedLit(Map("key1" -> 1, "key2" -> 2)))

Spark 1.3+ ( lit), 1.4+ ( array, struct), 2.0+ ( map):

Das zweite Argument für DataFrame.withColumnsollte a sein, Columndaher müssen Sie ein Literal verwenden:

from pyspark.sql.functions import lit

df.withColumn('new_column', lit(10))

Wenn Sie komplexe Spalten benötigen, können Sie diese mit folgenden Blöcken erstellen array:

from pyspark.sql.functions import array, create_map, struct

df.withColumn("some_array", array(lit(1), lit(2), lit(3)))
df.withColumn("some_struct", struct(lit("foo"), lit(1), lit(.3)))
df.withColumn("some_map", create_map(lit("key1"), lit(1), lit("key2"), lit(2)))

Genau die gleichen Methoden können in Scala verwendet werden.

import org.apache.spark.sql.functions.{array, lit, map, struct}

df.withColumn("new_column", lit(10))
df.withColumn("map", map(lit("key1"), lit(1), lit("key2"), lit(2)))

Namen für bereitzustellen structsVerwendung entweder aliasauf jedem Feld:

df.withColumn(
    "some_struct",
    struct(lit("foo").alias("x"), lit(1).alias("y"), lit(0.3).alias("z"))
 )

oder castauf das ganze Objekt

df.withColumn(
    "some_struct", 
    struct(lit("foo"), lit(1), lit(0.3)).cast("struct<x: string, y: integer, z: double>")
 )

Es ist auch möglich, obwohl langsamer, eine UDF zu verwenden.

Hinweis :

Dieselben Konstrukte können verwendet werden, um konstante Argumente an UDFs oder SQL-Funktionen zu übergeben.


1
Für andere, die dies zum Implementieren verwenden ... gibt die withColumn-Methode einen neuen DataFrame zurück, indem sie eine Spalte hinzufügt oder die vorhandene Spalte mit demselben Namen ersetzt. Daher müssen Sie die Ergebnisse df neu zuweisen oder einer neuen Variablen zuweisen. Zum Beispiel `df = df.withColumn ('new_column', lit (10)) '
Even Mien

Können wir bei jeder Iteration die Werte in der Spalte ändern? Ich habe es bereits versucht, for i in range(len(item)) : df.withColumn('new_column', lit({}).format(i)) aber das funktioniert nicht
Tracy

29

In Spark 2.2 gibt es zwei Möglichkeiten, einen konstanten Wert in einer Spalte in DataFrame hinzuzufügen:

1) Verwenden lit

2) Verwenden typedLit.

Der Unterschied zwischen beiden besteht darin, dass typedLitauch parametrisierte Scala-Typen wie List, Seq und Map verarbeitet werden können

Beispiel DataFrame:

val df = spark.createDataFrame(Seq((0,"a"),(1,"b"),(2,"c"))).toDF("id", "col1")

+---+----+
| id|col1|
+---+----+
|  0|   a|
|  1|   b|
+---+----+

1) Verwenden von lit: Hinzufügen eines konstanten Zeichenfolgenwerts in einer neuen Spalte mit dem Namen newcol:

import org.apache.spark.sql.functions.lit
val newdf = df.withColumn("newcol",lit("myval"))

Ergebnis:

+---+----+------+
| id|col1|newcol|
+---+----+------+
|  0|   a| myval|
|  1|   b| myval|
+---+----+------+

2) Verwenden von typedLit:

import org.apache.spark.sql.functions.typedLit
df.withColumn("newcol", typedLit(("sample", 10, .044)))

Ergebnis:

+---+----+-----------------+
| id|col1|           newcol|
+---+----+-----------------+
|  0|   a|[sample,10,0.044]|
|  1|   b|[sample,10,0.044]|
|  2|   c|[sample,10,0.044]|
+---+----+-----------------+

Könnten Sie die vollständige Version zusammen mit Import Statement teilen
Ayush Vatsyayan

Funkenversion 2.2.1. Die import-Anweisung stammt von pyspark.sql.functions import typedLit. Versuchen Sie auch die von Ihnen oben geteilte.
Braj
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.