我有一个pyspark数据框,如下所示:
+---------------+---+---+---+---+---+---+
| Entity| id| 7| 15| 19| 21| 27|
+---------------+---+---+---+---+---+---+
| a| 0| 0| 1| 0| 0| 0|
| b| 1| 0| 0| 0| 1| 0|
| c| 2| 0| 0| 0| 1| 0|
| d| 3| 2| 0| 0| 0| 0|
| e| 4| 0| 3| 0| 0| 0|
| f| 5| 0| 25| 0| 0| 0|
| g| 6| 2| 0| 0| 0| 0|
我想在每个列中的所有元素中添加0到1之间的随机值,实体和实体ID。实体和实体之后可以有任意数量的列。 id(在这种情况下有5个,但可能有100个,或1000个或更多)。
这是我到目前为止所拥有的:
random_df = data.select("*").rdd.map(
lambda x, r=random: [Row(str(row)) if isinstance(row, unicode) else
Row(float(r.random() + row)) for row in x]).toDF(data.columns)
但是,这也会在id列中添加一个随机值。通常情况下,如果我之前知道元素的数量,并且我知道它们将被修复,我可以使用
在lambda表达式中明确地调用它们。data.select("*").rdd.map(lambda (a,b,c,d,e,f,g):
Row(a,b, r.random() + c r.random() + d, r.random() + e, r.random()
+ f, r.random() + g))
但是,不幸的是,由于不知道我将提前有多少列,这不会起作用。想法?我真的很感激帮助!
编辑:我还应该注意'id'是调用的结果:
data = data.withColumn("id", monotonically_increasing_id())
添加此编辑,因为我尝试将列'id'转换为StringType,以便我的'isinstance(row,unicode)'会触发,但我没有成功。以下代码:
data = data.withColumn("id", data['id'].cast(StringType)
结果:
raise TypeError("unexpected type: %s" % type(dataType))
TypeError: unexpected type: <class 'pyspark.sql.types.DataTypeSingleton'>
答案 0 :(得分:2)
您应该在.cast("string")
列上尝试id
。
import random
import pyspark.sql.functions as f
from pyspark.sql.types import Row
df = sc.parallelize([
['a', 0, 1, 0, 0, 0],
['b', 0, 0, 0, 1, 0],
['c', 0, 0, 0, 1, 0],
['d', 2, 0, 0, 0, 0],
['e', 0, 3, 0, 0, 0],
['f', 0, 25,0, 0, 0],
['g', 2, 0, 0, 0, 0],
]).toDF(('entity', '7', '15', '19', '21', '27'))
df = df.withColumn("id", f.monotonically_increasing_id())
df = df.withColumn("id_string", df["id"].cast("string")).drop("id")
df.show()
random_df = df.select("*").rdd.map(
lambda x, r=random: [Row(str(row)) if isinstance(row, unicode) else
Row(float(r.random() + row)) for row in x]).toDF(df.columns)
random_df.show()
希望这有帮助!