Làm cách nào để thêm một cột không đổi trong Spark DataFrame?


137

Tôi muốn thêm một cột trong một DataFramegiá trị tùy ý (tương tự cho mỗi hàng). Tôi gặp lỗi khi sử dụng withColumnnhư sau:

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'

Dường như tôi có thể lừa chức năng hoạt động như tôi muốn bằng cách thêm và trừ một trong các cột khác (để chúng thêm vào số 0) và sau đó thêm số tôi muốn (10 trong trường hợp này):

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

Điều này là cực kỳ hack, phải không? Tôi cho rằng có một cách hợp pháp hơn để làm điều này?

Câu trả lời:


219

Spark 2.2+

Spark 2.2 giới thiệu typedLitđể hỗ trợ Seq, MapTuples( SPARK-19254 ) và các cuộc gọi sau nên được hỗ trợ (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):

Đối số thứ hai DataFrame.withColumnphải là một Columnvì vậy bạn phải sử dụng một nghĩa đen:

from pyspark.sql.functions import lit

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

Nếu bạn cần các cột phức tạp, bạn có thể xây dựng các cột này bằng cách sử dụng các khối như 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)))

Chính xác các phương pháp tương tự có thể được sử dụng trong Scala.

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

Để cung cấp tên để structssử dụng hoặc aliastrên mỗi lĩnh vực:

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

hoặc casttrên toàn bộ đối tượng

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

Mặc dù cũng có thể sử dụng UDF.

Lưu ý :

Các cấu trúc tương tự có thể được sử dụng để truyền các đối số không đổi cho các hàm UDF hoặc SQL.


1
Đối với những người khác sử dụng điều này để triển khai ... phương thức withColumn trả về một DataFrame mới bằng cách thêm một cột hoặc thay thế cột hiện có cùng tên, vì vậy bạn sẽ cần gán lại kết quả cho df hoặc gán cho một biến mới. Ví dụ: `df = df.withColumn ('new_column', lit (10)) '
Ngay cả Mien

với mỗi lần lặp, chúng ta có thể thay đổi các giá trị bên trong cột không? tôi đã thử nó for i in range(len(item)) : df.withColumn('new_column', lit({}).format(i)) nhưng nó không hoạt động
Tracy

29

Trong spark 2.2, có hai cách để thêm giá trị không đổi trong một cột trong DataFrame:

1) Sử dụng lit

2) Sử dụng typedLit.

Sự khác biệt giữa hai loại này typedLitcũng có thể xử lý các loại scala được tham số hóa, ví dụ như List, Seq và Map

Khung dữ liệu mẫu:

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

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

1) Sử dụng lit: Thêm giá trị chuỗi không đổi trong cột mới có tên newcol:

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

Kết quả:

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

2) Sử dụng typedLit:

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

Kết quả:

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

Bạn có thể chia sẻ phiên bản hoàn chỉnh cùng với tuyên bố nhập khẩu
Ayush Vatsyayan

phiên bản tia lửa 2.2.1. báo cáo nhập khẩu là từ pyspark.sql.fifts nhập typedLit. Cũng đã thử một chia sẻ của bạn ở trên.
braj
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.