ฉันจะเพิ่มคอลัมน์ใหม่ใน Spark DataFrame (โดยใช้ PySpark) ได้อย่างไร


129

ฉันมี Spark DataFrame (ใช้ PySpark 1.5.1) และต้องการเพิ่มคอลัมน์ใหม่

ฉันได้ลองทำสิ่งต่อไปนี้แล้ว แต่ไม่ประสบความสำเร็จ:

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

ดังนั้นฉันจะเพิ่มคอลัมน์ใหม่ (ตาม Python vector) ไปยัง DataFrame ที่มีอยู่ด้วย PySpark ได้อย่างไร

คำตอบ:


208

คุณไม่สามารถเพิ่มคอลัมน์โดยพลการDataFrameใน Spark คอลัมน์ใหม่สามารถสร้างได้โดยใช้ตัวอักษรเท่านั้น (ประเภทตัวอักษรอื่น ๆ อธิบายไว้ในวิธีการเพิ่มคอลัมน์ค่าคงที่ใน 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|
## +---+---+-----+---+--------------------+----+-------------------+

ฟังก์ชันในตัวที่ชาญฉลาดด้านประสิทธิภาพ ( pyspark.sql.functions) ซึ่งแมปกับนิพจน์ของตัวเร่งปฏิกิริยามักเป็นที่ต้องการมากกว่าฟังก์ชันที่กำหนดโดยผู้ใช้ Python

หากคุณต้องการเพิ่มเนื้อหาของ RDD โดยพลการเป็นคอลัมน์คุณสามารถทำได้


1
"คอลัมน์ใหม่สามารถสร้างได้โดยใช้ตัวอักษรเท่านั้น" ในบริบทนี้หมายถึงอะไร
timbram

เอกสารของ Spark นั้นยอดเยี่ยมมากโปรดดู df.withColumn spark.apache.org/docs/2.1.0/api/python/…
Steven Black

10
เอกสารประกอบของ Spark นั้น "ยอดเยี่ยม" เพียงอย่างเดียวที่จะทิ้งการใช้งานได้อย่างยอดเยี่ยมจนถึงแบบฝึกหัดสำหรับผู้อ่านที่ชาญฉลาด Spark (และ Pyspark) ครอบคลุมโครงสร้างข้อมูลสวนสัตว์ที่แท้จริงโดยมีคำแนะนำเพียงเล็กน้อยหรือไม่มีเลยเกี่ยวกับวิธีการแปลงข้อมูล ตรงประเด็น: การเพิ่มจำนวนคำถามเช่นเดียวกับคำถามนี้
shadowtalker

62

ในการเพิ่มคอลัมน์โดยใช้ 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|
## +---+---+-----+---------+

30

สำหรับSpark 2.0

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

1
ต้องเป็น df.select ('*', (df.age + 10) .alias ('agePlusTen'))
Frank B.

1
ขอบคุณและหากคุณป้อนdf = df.select('*', (df.age + 10).alias('agePlusTen'))คุณกำลังเพิ่มคอลัมน์ตามอำเภอใจอย่างมีประสิทธิภาพตามที่ @ zero323 เตือนเราข้างต้นเป็นไปไม่ได้เว้นแต่จะมีบางอย่างผิดปกติในการทำสิ่งนี้ใน Spark ใน Pandas เป็นวิธีมาตรฐาน ..
กระวาน

มีรุ่นนี้สำหรับ pySpark หรือไม่?
Tagar

@Tagar ตัวอย่างด้านบนคือ python
Luke W

1
@GeoffreyAnderson,df.select('*', df.age + 10, df.age + 20)
Mark Rajcok

2

มีหลายวิธีที่เราสามารถเพิ่มคอลัมน์ใหม่ใน pySpark

ก่อนอื่นมาสร้าง DataFrame อย่างง่าย

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

ทีนี้ลองเพิ่มค่าคอลัมน์เป็นสองเท่าแล้วเก็บไว้ในคอลัมน์ใหม่ PFB มีแนวทางที่แตกต่างกันเล็กน้อยเพื่อให้บรรลุเป้าหมายเดียวกัน

# 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()

สำหรับตัวอย่างเพิ่มเติมและคำอธิบายเกี่ยวกับฟังก์ชั่นจุดประกาย DataFrame คุณสามารถเยี่ยมชมของฉันบล็อก

ฉันหวังว่านี่จะช่วยได้.


0

คุณสามารถกำหนดใหม่ได้udfเมื่อเพิ่มcolumn_name:

u_f = F.udf(lambda :yourstring,StringType())
a.select(u_f().alias('column_name')

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

คุณต้องโทรStringType().
gberger

0

ฉันต้องการเสนอตัวอย่างทั่วไปสำหรับกรณีการใช้งานที่คล้ายกันมาก:

Use Case: ฉันมี 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) ฉันอ่าน csv ดั้งเดิมโดยใช้ spark.read และเรียกมันว่า "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

วิธีที่ง่ายที่สุดในการเพิ่มคอลัมน์คือการใช้ "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()

0

เราสามารถเพิ่มคอลัมน์เพิ่มเติมใน 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()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.