Bagaimana cara menambahkan kolom baru ke Spark DataFrame (menggunakan PySpark)?

129

Saya memiliki Spark DataFrame (menggunakan PySpark 1.5.1) dan ingin menambahkan kolom baru.

Saya telah mencoba yang berikut ini tetapi tidak berhasil:

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"])

Juga mendapat kesalahan menggunakan ini:

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

Jadi bagaimana cara menambahkan kolom baru (berdasarkan vektor Python) ke DataFrame yang ada dengan PySpark?

Boris
sumber

Jawaban:

208

Anda tidak dapat menambahkan kolom arbitrer ke a DataFramedi Spark. Kolom baru hanya dapat dibuat dengan menggunakan literal (tipe literal lainnya dijelaskan di Bagaimana cara menambahkan kolom konstan di 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|
## +---+---+-----+---+

mengubah kolom yang sudah ada:

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...|
## +---+---+-----+---+--------------------+

termasuk menggunakan 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|
## +---+---+-----+---+--------------------+----+

atau dihasilkan dengan function / 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|
## +---+---+-----+---+--------------------+----+-------------------+

Dari segi kinerja, fungsi built-in ( pyspark.sql.functions), yang memetakan ke ekspresi Catalyst, biasanya lebih disukai daripada fungsi yang ditentukan pengguna Python.

Jika Anda ingin menambahkan konten RDD sewenang-wenang sebagai kolom, Anda bisa

nol323
sumber
1
"Kolom baru hanya dapat dibuat dengan menggunakan literal" Apa sebenarnya arti literal dalam konteks ini?
timbram
Dokumentasi Spark sangat bagus, lihat df.withColumn spark.apache.org/docs/2.1.0/api/python/…
Steven Black
10
Dokumentasi Spark "hebat" hanya karena ia meninggalkan sebagian besar penggunaan hingga latihan bagi pembaca yang cerdik. Spark (dan Pyspark) mencakup kebun binatang struktur data yang sesungguhnya, dengan sedikit atau tanpa instruksi tentang cara mengonversinya. Contoh kasus: banyaknya pertanyaan seperti ini.
shadowtalker
62

Untuk menambahkan kolom menggunakan 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|
## +---+---+-----+---------+
Mark Rajcok
sumber
30

Untuk Spark 2.0

# assumes schema has 'age' column 
df.select('*', (df.age + 10).alias('agePlusTen'))
Luke W.
sumber
1
Perlu df.select ('*', (df.age + 10) .alias ('agePlusTen'))
Frank B.
1
Terima kasih, dan jika Anda masuk, df = df.select('*', (df.age + 10).alias('agePlusTen'))Anda secara efektif menambahkan kolom arbitrer karena @ zero323 memperingatkan kami di atas tidak mungkin, kecuali ada yang salah dengan melakukan ini di Spark, di Pandas itu cara standar ..
kapulaga
Apakah ada versi ini untuk pySpark?
Tagar
@Tagar Cuplikan di atas adalah python.
Luke W
1
@GeoffreyAnderson,df.select('*', df.age + 10, df.age + 20)
Mark Rajcok
2

Ada banyak cara untuk menambahkan kolom baru di pySpark.

Mari pertama-tama buat DataFrame sederhana.

date = [27, 28, 29, None, 30, 31]
df = spark.createDataFrame(date, IntegerType())

Sekarang mari kita coba menggandakan nilai kolom dan menyimpannya di kolom baru. PFB beberapa pendekatan berbeda untuk mencapai hal yang sama.

# Approach - 1 : using withColumn function
df.withColumn("double", df.value * 2).show()

# Approach - 2 : using select with alias function.
df.select("*", (df.value * 2).alias("double")).show()

# Approach - 3 : using selectExpr function with as clause.
df.selectExpr("*", "value * 2 as double").show()

# Approach - 4 : Using as clause in SQL statement.
df.createTempView("temp")
spark.sql("select *, value * 2 as double from temp").show()

Untuk lebih banyak contoh dan penjelasan tentang fungsi spark DataFrame, Anda dapat mengunjungi blog saya .

Saya harap ini membantu.

neeraj bhadani
sumber
0

Anda dapat menentukan yang baru udfsaat menambahkan column_name:

u_f = F.udf(lambda :yourstring,StringType())
a.select(u_f().alias('column_name')
Allen211
sumber
0
from pyspark.sql.functions import udf
from pyspark.sql.types import *
func_name = udf(
    lambda val: val, # do sth to val
    StringType()
)
df.withColumn('new_col', func_name(df.old_col))
DeFOX
sumber
Anda perlu menelepon StringType().
gberger
0

Saya ingin menawarkan contoh umum untuk kasus penggunaan yang sangat mirip:

Kasus Penggunaan: Saya memiliki csv yang terdiri dari:

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

Saya perlu melakukan beberapa transformasi dan csv akhir harus terlihat seperti ini

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

Saya perlu melakukan ini karena ini adalah skema yang ditentukan oleh beberapa model dan saya perlu data akhir saya agar dapat dioperasikan dengan SQL Massal Inserts dan hal-hal semacam itu.

begitu:

1) Saya membaca csv asli menggunakan spark.read dan menyebutnya "df".

2) Saya melakukan sesuatu pada data.

3) Saya menambahkan kolom nol menggunakan skrip ini:

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)

Dengan cara ini, Anda dapat menyusun skema Anda setelah memuat csv (juga akan berfungsi untuk menyusun ulang kolom jika Anda harus melakukan ini untuk banyak tabel).

bloodrootfc.dll
sumber
0

Cara termudah untuk menambahkan kolom adalah dengan menggunakan "withColumn". Karena dataframe dibuat menggunakan sqlContext, Anda harus menentukan skema atau secara default dapat tersedia di dataset. Jika skema ditentukan, beban kerja menjadi membosankan saat berubah setiap saat.

Di bawah ini adalah contoh yang bisa Anda pertimbangkan:

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()
Swaminathan Meenakshisundaram
sumber
0

Kami dapat menambahkan kolom tambahan ke DataFrame secara langsung dengan langkah-langkah di bawah ini:

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()
yogesh
sumber