Як додати новий стовпець до 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) до існуючої DataFrame з PySpark?

Відповіді:


208

Ви не можете додати довільну колонку до 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|
## +---+---+-----+---+--------------------+----+-------------------+

Вбудовані функції ( pyspark.sql.functions), що залежать від продуктивності ( ), які позначають вираз Catalyst, зазвичай віддають перевагу над визначеними користувачем функціями Python.

Якщо ви хочете додати вміст довільної RDD як стовпець, ви можете


1
"Нові стовпці можна створити лише за допомогою літералів" Що саме означає літерали в цьому контексті?
тембрам

Документація Іскра чудова, дивіться df.withColumn spark.apache.org/docs/2.1.0/api/python/…
Стівен Блек

10
Документація на іскри "чудова" лише тим, що вона залишає великі обсяги використання аж до вправ для проникливого читача. Іскра (і 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'))
Френк Б.

1
Дякую, і якщо ви вводите, df = df.select('*', (df.age + 10).alias('agePlusTen'))ви фактично додаєте довільну колонку, як @ zero323 попереджав нас вище, було неможливо, якщо тільки щось не так з цим в Spark, у Pandas - це стандартний спосіб ..
cardamom

Чи існує версія цього для pySpark?
Тагар

@Tagar Вгорі фрагмент - пітон.
Лука Ш

1
@GeoffreyAnderson,df.select('*', df.age + 10, df.age + 20)
Марк Райкок

2

Існує кілька способів додавання нового стовпця в pySpark.

Спочатку створимо просту DataFrame.

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

Тепер спробуємо подвоїти значення стовпця і зберегти його в новому стовпчику. У ПФБ кілька різних підходів для досягнення того ж.

# 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

Я хотів би запропонувати узагальнений приклад для дуже подібного випадку використання:

Case 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 і подібними речами.

так:

1) Я читаю оригінальний csv за допомогою spark.read і називаю його "df".

2) Я щось роблю з даними.

3) Я додаю нульові стовпці за допомогою цього сценарію:

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()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.