我有一个数据帧(D1),如下所示:
col1 | col2 | col3 | col4
22 | null | 23 | 56
12 | 54 | 22 | 36
48 | null | null | 45
null | 32 | 13 | 6
23 | null | 43 | 8
67 | 54 | 56 | null
null | 32 | 32 | 6
3 | 54 | 64 | 8
67 | 4 | 23 | null
另一个数据帧(D2):
col_name | value
col 1 | 15
col 2 | 26
col 3 | 38
col 4 | 41
我想用D2中与每一列相对应的值替换D1中每一列的空值。
所以预期的输出将是:
col1 | col2 | col3 | col4
22 | 26 | 23 | 56
12 | 54 | 22 | 36
48 | 26 | 38 | 45
15 | 32 | 13 | 6
23 | 26 | 43 | 8
67 | 54 | 56 | 41
15 | 32 | 32 | 6
3 | 54 | 64 | 8
67 | 4 | 23 | 41
我想知道如何在PySpark数据帧中实现这一目标。 干杯!
答案 0 :(得分:1)
这是一种方法,但是由于我们使用的是crossJoin
,所以它可能不是最有效的,但是由于D2
相对较小,应该可以。其他方式可以是udf
。
# Creating the DataFrame
values = [(22,None,23,56),(12,54,22,36),(48,None,None,45),
(None,32,13,6),(23,None,43,8),(67,54,56,None),
(None,32,32,6),(3,54,64,8),(67,4,23,None)]
D1 = sqlContext.createDataFrame(values,['col1','col2','col3','col4'])
D1.show()
+----+----+----+----+
|col1|col2|col3|col4|
+----+----+----+----+
| 22|null| 23| 56|
| 12| 54| 22| 36|
| 48|null|null| 45|
|null| 32| 13| 6|
| 23|null| 43| 8|
| 67| 54| 56|null|
|null| 32| 32| 6|
| 3| 54| 64| 8|
| 67| 4| 23|null|
+----+----+----+----+
我们需要迭代列的列表,因此下面的代码对此进行了说明。
list_columns = D1.columns
print(list_columns)
['col1', 'col2', 'col3', 'col4']
创建第二个DataFrame。
D2 = sqlContext.createDataFrame([('col1',15),('col2',26),('col3',38),('col4',41)],['col_name','value'])
D2.show()
+--------+-----+
|col_name|value|
+--------+-----+
| col1| 15|
| col2| 26|
| col3| 38|
| col4| 41|
+--------+-----+
让我们pivot
DataFrame D2,以便我们可以将其附加到所有列中。
#Pivoting and then renaming the column
D2_new = D2.groupBy().pivot('col_name').sum('value')
D2_new = D2_new.select(*[col(c).alias(c+'_x') for c in D2_new.columns])
D2_new.show()
+------+------+------+------+
|col1_x|col2_x|col3_x|col4_x|
+------+------+------+------+
| 15| 26| 38| 41|
+------+------+------+------+
最后使用crossJoin,我们将它们附加-
# Appending the columns
D1 = D1.crossJoin(D2_new)
D1.show()
+----+----+----+----+------+------+------+------+
|col1|col2|col3|col4|col1_x|col2_x|col3_x|col4_x|
+----+----+----+----+------+------+------+------+
| 22|null| 23| 56| 15| 26| 38| 41|
| 12| 54| 22| 36| 15| 26| 38| 41|
| 48|null|null| 45| 15| 26| 38| 41|
|null| 32| 13| 6| 15| 26| 38| 41|
| 23|null| 43| 8| 15| 26| 38| 41|
| 67| 54| 56|null| 15| 26| 38| 41|
|null| 32| 32| 6| 15| 26| 38| 41|
| 3| 54| 64| 8| 15| 26| 38| 41|
| 67| 4| 23|null| 15| 26| 38| 41|
+----+----+----+----+------+------+------+------+
一旦获得了主要的DataFrame
,我们就可以使用简单的when-otherwise
构造通过在列列表上运行循环来进行替换。
# Finally doing the replacement.
for c in list_columns:
D1 = D1.withColumn(c,when(col(c).isNull(),col(c+'_x')).otherwise(col(c))).drop(col(c+'_x'))
D1.show()
+----+----+----+----+
|col1|col2|col3|col4|
+----+----+----+----+
| 22| 26| 23| 56|
| 12| 54| 22| 36|
| 48| 26| 38| 45|
| 15| 32| 13| 6|
| 23| 26| 43| 8|
| 67| 54| 56| 41|
| 15| 32| 32| 6|
| 3| 54| 64| 8|
| 67| 4| 23| 41|
+----+----+----+----+
答案 1 :(得分:0)
IIUC,您可以创建一个column_name:value
映射,然后在每一列上执行fillna()
:
mapping = { row.col_name.replace(' ',''):row.value for row in D2.collect() }
#{u'col1': 15.0, u'col2': 26.0, u'col3': 38.0, u'col4': 41.0}
# fillna on col1 for testing
D1.fillna(mapping['col1'], subset=['col1']).show()
+----+----+----+----+
|col1|col2|col3|col4|
+----+----+----+----+
|22.0| NaN|23.0|56.0|
|12.0|54.0|22.0|36.0|
|48.0| NaN| NaN|45.0|
|15.0|32.0|13.0| 6.0|
|23.0| NaN|43.0| 8.0|
|67.0|54.0|56.0| NaN|
|15.0|32.0|32.0| 6.0|
| 3.0|54.0|64.0| 8.0|
|67.0| 4.0|23.0| NaN|
+----+----+----+----+
# use a reduce function to handle all columns
df_new = reduce(lambda d,c: d.fillna(mapping[c], subset=[c]), D1.columns, D1)
或使用列表理解
from pyspark.sql.functions import isnan, when, col
df_new = D1.select([ when(isnan(c), mapping[c]).otherwise(col(c)).alias(c) for c in D1.columns ])
注意:对于StringType列,将上面的isnan()
替换为isnull()