【发布时间】:2016-03-08 22:33:20
【问题描述】:
有两列:
ID Text
1 a
2 b
3 c
我怎样才能用这样的虚拟变量创建矩阵:
ID a b c
1 1 0 0
2 0 1 0
3 0 0 1
使用 pyspark 库及其功能?
【问题讨论】:
标签: python apache-spark pyspark
有两列:
ID Text
1 a
2 b
3 c
我怎样才能用这样的虚拟变量创建矩阵:
ID a b c
1 1 0 0
2 0 1 0
3 0 0 1
使用 pyspark 库及其功能?
【问题讨论】:
标签: python apache-spark pyspark
另一种解决方案是使用 Spark 的 pivot 方法,该方法自 Spark 1.6.0 以来一直存在。
例子:
from pyspark.sql import functions as F
df = sqlContext.createDataFrame([
(1, "a"),
(2, "b"),
(3, "c"),],
["ID", "Text"])
pivoted = df.groupBy("ID").pivot("Text").agg(F.lit(1))
pivoted.show()
# +---+----+----+----+
# | ID| a| b| c|
# +---+----+----+----+
# | 1| 1|null|null|
# | 3|null|null| 1|
# | 2|null| 1|null|
# +---+----+----+----+
要消除缺失值,只需使用na 方法:
pivoted.na.fill(0).show()
# +---+---+---+---+
# | ID| a| b| c|
# +---+---+---+---+
# | 1| 1| 0| 0|
# | 3| 0| 0| 1|
# | 2| 0| 1| 0|
# +---+---+---+---+
Pivoting 比 solution proposed by ksindi 更通用,因为它可以聚合数字。话虽这么说,ksindi 提出的解决方案在这种特殊情况下更有效,因为它只需要对数据进行一次传递,如果考虑到获取类别的传递,则需要两次。对于旋转,您还可以将类别作为第二个位置参数添加到pivot,从而提高效率。但是groupBy 调用已经引起了洗牌,这使得这种方法变慢了。
注意:groupBy 调用默认假定示例中的ID 列包含唯一值以获取所需的输出。如果示例数据框看起来像:
df = sqlContext.createDataFrame([
(1, "a"),
(2, "b"),
(3, "c"),
(3, "a")],
["ID", "Text"])
这个解决方案的结果是
df.groupBy("ID").pivot("Text").agg(F.lit(1)).na.fill(0).show()
# +---+---+---+---+
# | ID| a| b| c|
# +---+---+---+---+
# | 1| 1| 0| 0|
# | 3| 1| 0| 1|
# | 2| 0| 1| 0|
# +---+---+---+---+
而映射解决方案最终会是
df.select("ID", *exprs).show()
# +---+---+---+---+
# | ID| c| b| a|
# +---+---+---+---+
# | 1| 0| 0| 1|
# | 2| 0| 1| 0|
# | 3| 1| 0| 0|
# | 3| 0| 0| 1|
# +---+---+---+---+
【讨论】:
F.monotonically_increasing_id 将有助于区分行,充当 .groupBy 表达式。
from pyspark.sql import functions as F
df = sqlContext.createDataFrame([
(1, "a"),
(2, "b"),
(3, "c"),
], ["ID", "Text"])
categories = df.select("Text").distinct().rdd.flatMap(lambda x: x).collect()
exprs = [F.when(F.col("Text") == category, 1).otherwise(0).alias(category)
for category in categories]
df.select("ID", *exprs).show()
输出
+---+---+---+---+
| ID| a| b| c|
+---+---+---+---+
| 1| 1| 0| 0|
| 2| 0| 1| 0|
| 3| 0| 0| 1|
+---+---+---+---+
【讨论】:
如果虚拟变量用于建模,您可以使用 OneHotEncoder /OneHotEncoderEstimator(取决于 pyspark 的版本)。
可以在Spark MLlib Guide中展示一个示例。
请注意,如果您需要删除一列以防止线性依赖(如回归的情况),您应该使用dropLast=True。
【讨论】: