Pyspark对行进行迭代,并使用结果列上的逻辑计算计数器
我有pyspark dataframe中的数据(这是一个有900M行的非常大的表) 这是我掌握的数据Pyspark对行进行迭代,并使用结果列上的逻辑计算计数器,pyspark,Pyspark,我有pyspark dataframe中的数据(这是一个有900M行的非常大的表) 这是我掌握的数据 +-------+---------+----------+ | key| time| cond| +-------+---------+----------+ | 6| 3704| null| | 6| 74967| 1062| | 6|151565068| null| | 6|1549
+-------+---------+----------+
| key| time| cond|
+-------+---------+----------+
| 6| 3704| null|
| 6| 74967| 1062|
| 6|151565068| null|
| 6|154999554| null|
| 6|160595800| null|
| 6|166192324| null|
| 6|166549533| null|
| 6|171318946| null|
| 6|754759092| null|
| 6|754999359| 18882624|
| 6|755171746| 11381128|
| 6|761097038| null|
| 6|774496554| null|
| 6|930609982| null|
| 6|930809622| null|
| 1| 192427| null|
| 1| 192427| 2779|
| 1| 717931| null|
| 1| 1110573| null|
| 1| 1155854| null|
| 1| 70049289| null|
| 1| 70687548| null|
| 1| 71222733| null|
| 1| 85006084| null|
| 1| 85029676| null|
| 1| 85032605| 1424537|
| 1| 85240114| null|
| 1| 85573757| null|
| 1| 85710915| null|
| 1| 85870370| null|
+-------+---------+----------+
这就是我需要对数据帧执行的操作(中间步骤):
“result”列的逻辑如下:每个键都有一个运行计数器,如果“cond”列不为null,则将计数器归零
我们可以假设表是orderBy(“key”,asc(“time”))
我的最终结果实际上是平均值。行上的结果(每个键)条件不为null。
上述数据(最终结果)应如下所示:
我打算这样做:
df_results = df3[df3.cond.isNotNull()].groupby(['key']).agg(
F.expr("avg(result)").alias("avg_per_key")
)
我认为它应该工作,但也许没有中间步骤的话,有更好的方法。< /P>
如何在pyspark中高效地实现这一点?(记住数据集是巨大的)试试这个。计算结果的方法是在
条件下使用增量和,然后在另一个窗口中使用这些分组作为行数()-1的分区,以获得所需的结果过滤
之前的分组依据
应通过减少混洗
执行
from pyspark.sql import functions as F
from pyspark.sql.window import Window
w=Window().partitionBy("key").orderBy("time")
w1=Window().partitionBy("key","result").orderBy("time")
conditions=F.when((F.col("cond").isNotNull())&(F.col("lag").isNotNull()&\
F.col("lead").isNull()),F.lit(1))\
.when((F.col("cond").isNull())&(F.col("lag").isNotNull()),F.lit(1))\
.otherwise(F.lit(0))
df.withColumn("lag", F.lag("cond").over(w))\
.withColumn("lead", F.lead("cond").over(w))\
.withColumn("result",F.sum(conditions).over(w))\
.withColumn("result", F.row_number().over(w1)-1).filter("cond is not null")\
.groupBy("key").agg(F.mean(F.col("result")).alias("avg_per_key")).show()
#+---+------------------+
#|key| avg_per_key|
#+---+------------------+
#| 6|2.6666666666666665|
#| 1| 4.5|
#+---+------------------+
试试这个。计算结果的方法是在条件下使用增量和,然后在另一个窗口中使用这些分组作为行数()-1的分区,以获得所需的结果过滤
之前的分组依据
应通过减少混洗
执行
from pyspark.sql import functions as F
from pyspark.sql.window import Window
w=Window().partitionBy("key").orderBy("time")
w1=Window().partitionBy("key","result").orderBy("time")
conditions=F.when((F.col("cond").isNotNull())&(F.col("lag").isNotNull()&\
F.col("lead").isNull()),F.lit(1))\
.when((F.col("cond").isNull())&(F.col("lag").isNotNull()),F.lit(1))\
.otherwise(F.lit(0))
df.withColumn("lag", F.lag("cond").over(w))\
.withColumn("lead", F.lead("cond").over(w))\
.withColumn("result",F.sum(conditions).over(w))\
.withColumn("result", F.row_number().over(w1)-1).filter("cond is not null")\
.groupBy("key").agg(F.mean(F.col("result")).alias("avg_per_key")).show()
#+---+------------------+
#|key| avg_per_key|
#+---+------------------+
#| 6|2.6666666666666665|
#| 1| 4.5|
#+---+------------------+
这是我的解决方案,我不是说它是最优的,而是在我的情况下,当其他尝试使集群崩溃时,它起了作用。
我是spark的初学者,所以我知道这种方法可能会导致问题,因为它将数据集放入内存。
如果我有更多的时间玩它,我会尝试使用sortWithinPartitions
def handleRow(row):
temp = list(row[1])
temp = np.array([temp[x:x+2] for x in range(0, len(temp),2)])
temp[:,0] = temp[:,0].astype(float)
temp = temp[temp[:,0].argsort()]
avg_per_key= []
counter=0
for time,cond in temp:
if cond!=None:
avg_per_key.append(counter)
counter=0
else:
counter=counter+1
return [(row[0],-1 if len(avg_per_key)==0 else np.mean(avg_per_key))]
count = df3.rdd.map(lambda x: (x.key, (x.time, x.cond)))\
.reduceByKey(lambda a, b: a + b)\
.flatMap(handleRow)\
.collect()
这是我的解决方案,我不是说它是最优的,而是在我的情况下,当其他尝试使集群崩溃时,它起了作用。
我是spark的初学者,所以我知道这种方法可能会导致问题,因为它将数据集放入内存。
如果我有更多的时间玩它,我会尝试使用sortWithinPartitions
def handleRow(row):
temp = list(row[1])
temp = np.array([temp[x:x+2] for x in range(0, len(temp),2)])
temp[:,0] = temp[:,0].astype(float)
temp = temp[temp[:,0].argsort()]
avg_per_key= []
counter=0
for time,cond in temp:
if cond!=None:
avg_per_key.append(counter)
counter=0
else:
counter=counter+1
return [(row[0],-1 if len(avg_per_key)==0 else np.mean(avg_per_key))]
count = df3.rdd.map(lambda x: (x.key, (x.time, x.cond)))\
.reduceByKey(lambda a, b: a + b)\
.flatMap(handleRow)\
.collect()
我用windows lag尝试了一个类似的解决方案,但它对我不起作用,在运行2.5小时后崩溃了。我找到了另一个可行的解决方案,谢谢@justadev我很想看看这个解决方案是什么样子,以及它如何能够超越我的解决方案。为了社区的利益,请将其张贴在答案中,感谢教授的迟来回复。刚刚添加。@justadev感谢您的发布。你的解决方案会起作用,但它不是一种令人振奋的方式。正确使用的窗口函数总是优于任何rdd UDF,如urs。请记住,为了未来,我尝试了一个类似的解决方案,使用windows lag,但它对我不起作用,在运行2.5小时后崩溃了。我找到了另一个可行的解决方案,谢谢@justadev我很想看看这个解决方案是什么样子,以及它如何能够超越我的解决方案。为了社区的利益,请将其张贴在答案中,感谢教授的迟来回复。刚刚添加。@justadev感谢您的发布。你的解决方案会起作用,但它不是一种令人振奋的方式。正确使用的窗口函数总是优于任何rdd UDF,如urs。牢记未来