Подтвердить что ты не робот

Замените пустые строки значениями None/null в DataFrame

У меня есть Spark 1.5.0 DataFrame с сочетанием null и пустых строк в том же столбце. Я хочу преобразовать все пустые строки во всех столбцах в null (None, в Python). В DataFrame могут быть сотни столбцов, поэтому я стараюсь избегать жестко закодированных манипуляций с каждым столбцом.

См. мою попытку ниже, что приводит к ошибке.

from pyspark.sql import SQLContext
sqlContext = SQLContext(sc)

## Create a test DataFrame
testDF = sqlContext.createDataFrame([Row(col1='foo', col2=1), Row(col1='', col2=2), Row(col1=None, col2='')])
testDF.show()
## +----+----+
## |col1|col2|
## +----+----+
## | foo|   1|
## |    |   2|
## |null|null|
## +----+----+

## Try to replace an empty string with None/null
testDF.replace('', None).show()
## ValueError: value should be a float, int, long, string, list, or tuple

## A string value of null (obviously) doesn't work...
testDF.replace('', 'null').na.drop(subset='col1').show()
## +----+----+
## |col1|col2|
## +----+----+
## | foo|   1|
## |null|   2|
## +----+----+
4b9b3361

Ответ 1

Это так просто:

from pyspark.sql.functions import col, when

def blank_as_null(x):
    return when(col(x) != "", col(x)).otherwise(None)

dfWithEmptyReplaced = testDF.withColumn("col1", blank_as_null("col1"))

dfWithEmptyReplaced.show()
## +----+----+
## |col1|col2|
## +----+----+
## | foo|   1|
## |null|   2|
## |null|null|
## +----+----+

dfWithEmptyReplaced.na.drop().show()
## +----+----+
## |col1|col2|
## +----+----+
## | foo|   1|
## +----+----+

Если вы хотите заполнить несколько столбцов, вы можете, например, уменьшить:

to_convert = set([...]) # Some set of columns

reduce(lambda df, x: df.withColumn(x, blank_as_null(x)), to_convert, testDF)

или использовать понимание:

exprs = [
    blank_as_null(x).alias(x) if x in to_convert else x for x in testDF.columns]

testDF.select(*exprs)

Если вы хотите специально работать с строковыми полями, пожалуйста, ответьте robin-loxley.

Ответ 2

Мое решение намного лучше, чем все решения, которые я видел до сих пор, которые могут обрабатывать столько полей, сколько вы хотите, посмотрите на небольшую функцию следующим образом:

  // Replace empty Strings with null values
  private def setEmptyToNull(df: DataFrame): DataFrame = {
    val exprs = df.schema.map { f =>
      f.dataType match {
        case StringType => when(length(col(f.name)) === 0, lit(null: String).cast(StringType)).otherwise(col(f.name)).as(f.name)
        case _ => col(f.name)
      }
    }

    df.select(exprs: _*)
  }

Вы можете легко переписать функцию выше в Python.

Я узнал этот трюк из @liancheng

Ответ 3

Просто добавьте сверху нуль323 и ответы на душевые. Для преобразования всех полей StringType.

from pyspark.sql.types import StringType
string_fields = []
for i, f in enumerate(test_df.schema.fields):
    if isinstance(f.dataType, StringType):
        string_fields.append(f.name)