在DataFrame中用空/空值替换空字符串

dnl*_*rky 21 python dataframe apache-spark apache-spark-sql pyspark

我有一个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|
## +----+----+
Run Code Online (Sandbox Code Playgroud)

zer*_*323 29

这很简单:

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|
## +----+----+
Run Code Online (Sandbox Code Playgroud)

如果要填充多列,可以减少:

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

reduce(lambda df, x: df.withColumn(x, blank_as_null(x)), to_convert, testDF)
Run Code Online (Sandbox Code Playgroud)

或使用理解:

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

testDF.select(*exprs)
Run Code Online (Sandbox Code Playgroud)

如果要专门对字符串字段操作请检查答案罗宾洛克斯利.

  • 声明`.otherwise(None)`不是必需的.对于不匹配的条件,总是返回无(请参阅https://spark.apache.org/docs/latest/api/python/pyspark.sql.html#pyspark.sql.functions.when) (2认同)

sou*_*ine 10

我的解决方案比我到目前为止看到的所有解决方案要好得多,它可以处理你想要的多个字段,请看下面的小函数:

  // 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: _*)
  }
Run Code Online (Sandbox Code Playgroud)

您可以轻松地在Python中重写上面的函数.

我从@liancheng那里学到了这个技巧


Rob*_*ley 7

只需添加zero323和soulmachine的答案.转换所有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)
Run Code Online (Sandbox Code Playgroud)


blo*_*tfc 7

UDF效率不高。使用内置方法执行此操作的正确方法是:

df = df.withColumn('myCol', when(col('myCol') == '', None).otherwise(col('myCol')))
Run Code Online (Sandbox Code Playgroud)

  • 这绝对是正确的解决方案,使用内置函数可以在 Spark 方面进行大量优化。Python UDF 非常昂贵,因为 Spark 执行器(无论您是否使用 pyspark,它总是在 JVM 上运行)需要序列化每一行(准确地说是批量行),通过套接字将其发送到子 python 进程,评估你的Python函数,序列化结果并从套接字读回它 (2认同)