Pyspark:如何构建一列(包含负值和正值)的总和,其停止点为0
我认为一个例子比描述更能说明问题。 右边的“sum”列就是我要找的。 我试图通过比较领先和滞后来重建这一点,但这只适用于第一次总和通常以负值结束 仅将正值和负值分别相加也会得到另一个最终结果Pyspark:如何构建一列(包含负值和正值)的总和,其停止点为0,pyspark,sum,Pyspark,Sum,我认为一个例子比描述更能说明问题。 右边的“sum”列就是我要找的。 我试图通过比较领先和滞后来重建这一点,但这只适用于第一次总和通常以负值结束 仅将正值和负值分别相加也会得到另一个最终结果 如果有人知道如何在pyspark中解决这个问题,那就太好了 我会在这里使用pandas\u udf: from pyspark.sql.functions import pandas_udf, PandasUDFType pdf = pd.DataFrame({'g':[1]*8, 'id':range
如果有人知道如何在pyspark中解决这个问题,那就太好了 我会在这里使用
pandas\u udf
:
from pyspark.sql.functions import pandas_udf, PandasUDFType
pdf = pd.DataFrame({'g':[1]*8, 'id':range(8), 'value': [-1,1,-1,-1,1,1,-1,1]})
df = spark.createDataFrame(pdf)
df = df.withColumn('cumsum', F.lit(math.inf))
@pandas_udf(df.schema, PandasUDFType.GROUPED_MAP)
def _calc_cumsum(pdf):
pdf.sort_values(by=['id'], inplace=True, ascending=True)
cumsums = []
prev = 0
for v in pdf['value'].values:
prev = max(prev + v, 0)
cumsums.append(prev)
pdf['cumsum'] = cumsums
return pdf
df = df.groupby('g').apply(_calc_cumsum)
df.show()
结果是:
+---+---+-----+------+
| g| id|value|cumsum|
+---+---+-----+------+
| 1| 0| -1| 0.0|
| 1| 1| 1| 1.0|
| 1| 2| -1| 0.0|
| 1| 3| -1| 0.0|
| 1| 4| 1| 1.0|
| 1| 5| 1| 2.0|
| 1| 6| -1| 1.0|
| 1| 7| 1| 2.0|
+---+---+-----+------+
我会在这里使用
pandas\u udf
:
from pyspark.sql.functions import pandas_udf, PandasUDFType
pdf = pd.DataFrame({'g':[1]*8, 'id':range(8), 'value': [-1,1,-1,-1,1,1,-1,1]})
df = spark.createDataFrame(pdf)
df = df.withColumn('cumsum', F.lit(math.inf))
@pandas_udf(df.schema, PandasUDFType.GROUPED_MAP)
def _calc_cumsum(pdf):
pdf.sort_values(by=['id'], inplace=True, ascending=True)
cumsums = []
prev = 0
for v in pdf['value'].values:
prev = max(prev + v, 0)
cumsums.append(prev)
pdf['cumsum'] = cumsums
return pdf
df = df.groupby('g').apply(_calc_cumsum)
df.show()
结果是:
+---+---+-----+------+
| g| id|value|cumsum|
+---+---+-----+------+
| 1| 0| -1| 0.0|
| 1| 1| 1| 1.0|
| 1| 2| -1| 0.0|
| 1| 3| -1| 0.0|
| 1| 4| 1| 1.0|
| 1| 5| 1| 2.0|
| 1| 6| -1| 1.0|
| 1| 7| 1| 2.0|
+---+---+-----+------+
请先看图片,这里有一个testdataset(前3列)和计算步骤
“flag”列现在是另一种格式。我们还检查了数据源,意识到我们只需要处理1和-1条目。我们将1映射为0,将-1映射为1。现在,正如您在“结果”列中看到的,它的工作方式与exspected相同
代码如下:
w1 = Window.partitionBy('group').orderBy('order')
df_0 = tst.withColumn('edge_det',F.when(((F.col('flag')==0)&((F.lag('flag',default=1).over(w1))==1)),1).otherwise(0))
df_0 = df_0.withColumn('edge_cyl',F.sum('edge_det').over(w1))
df1 = df_0.withColumn('condition', F.when(F.col('edge_cyl')==0,0).otherwise(F.when(F.col('flag')==1,-1).otherwise(1)))
df1 =df1.withColumn('cond_sum',F.sum('condition').over(w1))
cond = (F.col('cond_sum')>=0)|(F.col('condition')==1)
df2 = df1.withColumn('new_cond',F.when(cond,F.col('condition')).otherwise(0))
df3 = df2.withColumn("result",F.sum('new_cond').over(w1))
请先看图片,这里有一个testdataset(前3列)和计算步骤
“flag”列现在是另一种格式。我们还检查了数据源,意识到我们只需要处理1和-1条目。我们将1映射为0,将-1映射为1。现在,正如您在“结果”列中看到的,它的工作方式与exspected相同
代码如下:
w1 = Window.partitionBy('group').orderBy('order')
df_0 = tst.withColumn('edge_det',F.when(((F.col('flag')==0)&((F.lag('flag',default=1).over(w1))==1)),1).otherwise(0))
df_0 = df_0.withColumn('edge_cyl',F.sum('edge_det').over(w1))
df1 = df_0.withColumn('condition', F.when(F.col('edge_cyl')==0,0).otherwise(F.when(F.col('flag')==1,-1).otherwise(1)))
df1 =df1.withColumn('cond_sum',F.sum('condition').over(w1))
cond = (F.col('cond_sum')>=0)|(F.col('condition')==1)
df2 = df1.withColumn('new_cond',F.when(cond,F.col('condition')).otherwise(0))
df3 = df2.withColumn("result",F.sum('new_cond').over(w1))
这是可行的,但我们也找到了一个没有熊猫和循环的解决方案。这对于大数据集来说工作得更快。我会马上把它寄出去。但感谢纽尔的快速解决方案!这是可行的,但我们也找到了一个没有熊猫和循环的解决方案。这对于大数据集来说工作得更快。我会马上把它寄出去。但感谢纽尔的快速解决方案!哦,我不知道你这里只有
1
和-1
。哦,我不知道你这里只有1
和-1
。