如何将空数组转换为空数?

时间:2018-01-03 06:31:53

标签: apache-spark pyspark apache-spark-sql pyspark-sql

我有以下数据帧,我需要将空数组转换为null。

+----+---------+-----------+
|  id|count(AS)|count(asdr)|
+----+---------+-----------+
|1110| [12, 45]|   [50, 55]|     
|1111|       []|         []|    
|1112| [45, 46]|   [50, 50]|   
|1113|       []|         []|
+----+---------+-----------+

我尝试过以下无效的代码。

df.na.fill("null").show()

预期输出应为

+----+---------+-----------+
|  id|count(AS)|count(asdr)|
+----+---------+-----------+
|1110| [12, 45]|   [50, 55]|     
|1111|     NUll|       NUll|    
|1112| [45, 46]|   [50, 50]|   
|1113|     NUll|       NUll|
+----+---------+-----------+

7 个答案:

答案 0 :(得分:4)

对于您的dataframe,您只需执行以下操作即可

from pyspark.sql import functions as F
df.withColumn("count(AS)", F.when((F.size(F.col("count(AS)")) == 0), F.lit(None)).otherwise(F.col("count(AS)"))) \
    .withColumn("count(asdr)", F.when((F.size(F.col("count(asdr)")) == 0), F.lit(None)).otherwise(F.col("count(asdr)"))).show()

您应该输出dataframe作为

+----+---------+-----------+
|  id|count(AS)|count(asdr)|
+----+---------+-----------+
|1110| [12, 45]|   [50, 55]|
|1111|     null|       null|
|1112| [45, 46]|   [50, 50]|
|1113|     null|       null|
+----+---------+-----------+

<强>更新

如果您有两个以上的数组列并且想要动态应用上述逻辑,则可以使用以下逻辑

from pyspark.sql import functions as F
for c in df.dtypes:
    if "array" in c[1]:
        df = df.withColumn(c[0], F.when((F.size(F.col(c[0])) == 0), F.lit(None)).otherwise(F.col(c[0])))
df.show()

下面,
df.dtypes将为您提供具有列名和数据类型的元组数组。至于问题中的数据框,它将是

[('id', 'bigint'), ('count(AS)', 'array<bigint>'), ('count(asdr)', 'array<bigint>')]

withColumn仅适用于数组("array" in c[1]),其中F.size(F.col(c[0])) == 0是检查when函数的条件,该函数检查大小阵列。如果条件为真,即空数组,则填充无,否则填充原始值。循环应用于所有数组列。

答案 1 :(得分:3)

我认为na.fill不可能,但这应该对你有用。该代码将所有空的ArrayType-columns转换为null,并将其他列保持原样:

import spark.implicits._
import org.apache.spark.sql.types.ArrayType
import org.apache.spark.sql.functions._

val df = Seq(
  (110, Seq.empty[Int]),
  (111, Seq(1,2,3))
).toDF("id","arr")

// get names of array-type columns
val arrColsNames = df.schema.fields.filter(f => f.dataType.isInstanceOf[ArrayType]).map(_.name)

// map all empty arrays to nulls
val emptyArraysAsNulls = arrColsNames.map(n => when(size(col(n))>0,col(n)).as(n))

// non-array-type columns, keep them as they are
val keepCols = df.columns.filterNot(arrColsNames.contains).map(col)

df
  .select((keepCols ++ emptyArraysAsNulls):_*)
  .show()

+---+---------+
| id|      arr|
+---+---------+
|110|     null|
|111|[1, 2, 3]|
+---+---------+

答案 2 :(得分:1)

您可以使用selectExpr

执行此操作
df_filled = df.selectExpr(
    "id",
    "if(size(column1)<=0, null, column1)",
    "if(size(column2)<=0, null, column2)",
    ...
)

答案 3 :(得分:1)

您需要检查数组类型列的size。像:

df.show()
+----+---+
|  id|arr|
+----+---+
|1110| []|
+----+---+

df.withColumn("arr", when(size(col("arr")) == 0 , lit(None)).otherwise(col("arr") ) ).show()

+----+----+
|  id| arr|
+----+----+
|1110|null|
+----+----+

答案 4 :(得分:1)

这里没有df.na.fill之类的简单解决方案。一种方法是循环遍历所有相关列并在适当时替换值。在scala中使用foldLeft的示例:

val columns = df.schema.filter(_.dataType.typeName == "array").map(_.name)

val df2 = columns.foldLeft(df)((acc, colname) => acc.withColumn(colname, 
    when(size(col(colname)) === 0, null).otherwise(col(colname))))

首先,提取所有数组类型的列,然后迭代这些列。由于size函数仅为数组类型的列定义,因此这是必要的步骤(并避免遍历所有列)。

使用数据框:

+----+--------+-----+
|  id|    col1| col2|
+----+--------+-----+
|1110|[12, 11]|   []|
|1111|      []| [11]|
|1112|   [123]|[321]|
+----+--------+-----+

结果如下:

+----+--------+-----+
|  id|    col1| col2|
+----+--------+-----+
|1110|[12, 11]| null|
|1111|    null| [11]|
|1112|   [123]|[321]|
+----+--------+-----+

答案 5 :(得分:1)

fib

请记住,它也不适用于pyspark。

答案 6 :(得分:0)

将Ramesh Maharajans作为参考。我找到了另一种使用UDF解决方法。希望这有助于您在数据框架上使用多个规则。

DF

|store|   1|   2|   3|
+-----+----+----+----+
|  103|[90]|  []|  []|
|  104|  []|[67]|[90]|
|  101|[34]|  []|  []|
|  102|[35]|  []|  []|
+-----+----+----+----+

使用下面的代码,导入import pyspark.sql.functions as psf 此代码适用于pyspark

def udf1(x :list):
    if x==[]: return "null"
    else: return x
udf2 = udf(udf1, ArrayType(IntegerType()))

for c in df.dtypes:
    if "array" in c[1]:
        df=df.withColumn(c[0],udf2(psf.col(c[0])))
df.show()

输出

|store|   1|   2|   3|
+-----+----+----+----+
|  103|[90]|null|null|
|  104|null|[67]|[90]|
|  101|[34]|null|null|
|  102|[35]|null|null|
+-----+----+----+----+