Pyspark:如何构建一列(包含负值和正值)的总和,其停止点为0

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

我认为一个例子比描述更能说明问题。 右边的“sum”列就是我要找的。

我试图通过比较领先和滞后来重建这一点,但这只适用于第一次总和通常以负值结束

仅将正值和负值分别相加也会得到另一个最终结果


如果有人知道如何在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