如何在pyspark中创建行并在给定的df中递增

如何在pyspark中创建行并在给定的df中递增,pyspark,apache-spark-sql,Pyspark,Apache Spark Sql,我想要的是基于给定的数据帧创建一个新行,如下所示: TEST_schema = StructType([StructField("date", StringType(), True),\ StructField("col1", IntegerType(), True), StructField("col2", IntegerType(

我想要的是基于给定的数据帧创建一个新行,如下所示:

TEST_schema = StructType([StructField("date", StringType(), True),\
                          StructField("col1", IntegerType(), True),
                          StructField("col2", IntegerType(), True)\
                          ])
TEST_data = [('2020-08-17',0,0),('2020-08-18',2,1),('2020-08-19',0,2),('2020-08-20',3,0),('2020-08-21',4,2),\
             ('2020-08-22',1,3),('2020-08-23',2,2),('2020-08-24',1,2),('2020-08-25',3,1)]
rdd3 = sc.parallelize(TEST_data)
TEST_df = sqlContext.createDataFrame(TEST_data, TEST_schema)
TEST_df = TEST_df.withColumn("date",to_date("date", 'yyyy-MM-dd'))
TEST_df.show() 

+----------+----+----+
|      date|col1|col2|
+----------+----+----+
|2020-08-17|   0|   0|
|2020-08-18|   2|   1|
|2020-08-19|   0|   2|
|2020-08-20|   3|   0|
|2020-08-21|   4|   2|
|2020-08-22|   1|   3|
|2020-08-23|   2|   2|
|2020-08-24|   1|   2|
|2020-08-25|   3|   1|
+----------+----+----+
from pyspark.sql.functions import current_date, col, lit

#columns used for Window partitionBy
cols_part = ['pcol1', 'pcol2']

df_today = TEST_df.select([
    (current_date() if c == 'date' else col(c) if c in cols_part else lit(None)).alias(c)
        for c in TEST_df.columns
]).distinct()

df_new = TEST_df.union(df_today)
假设我想计算今天的日期,它是
current\u date()
,假设我想计算
col1
,如下:
如果col1>0返回col1+col2,否则0
其中date==yesturday的日期,它将是
current\u date()-1

计算
col2
如下,
coalesce(滞后(col2),0)

因此,我的结果dataframe如下所示:

+----------+----+----+
|      date|col1|want|
+----------+----+----+
|2020-08-17|   0|   0|
|2020-08-18|   2|   0|
|2020-08-19|   0|   1|
|2020-08-20|   3|   2|
|2020-08-21|   4|   0|
|2020-08-22|   1|   2|
|2020-08-23|   2|   3|
|2020-08-24|   1|   2|
|2020-08-25|   3|   2|
|2020-08-26|   4|   1|
+----------+----+----+

如果我们使用
with column
(基于列)方法,这将非常容易,但我想知道如何对行执行此操作。我最初的想法是先按列计算,然后对其进行转置,使其基于行。

IIUC,您可以尝试以下方法:

TEST_schema = StructType([StructField("date", StringType(), True),\
                          StructField("col1", IntegerType(), True),
                          StructField("col2", IntegerType(), True)\
                          ])
TEST_data = [('2020-08-17',0,0),('2020-08-18',2,1),('2020-08-19',0,2),('2020-08-20',3,0),('2020-08-21',4,2),\
             ('2020-08-22',1,3),('2020-08-23',2,2),('2020-08-24',1,2),('2020-08-25',3,1)]
rdd3 = sc.parallelize(TEST_data)
TEST_df = sqlContext.createDataFrame(TEST_data, TEST_schema)
TEST_df = TEST_df.withColumn("date",to_date("date", 'yyyy-MM-dd'))
TEST_df.show() 

+----------+----+----+
|      date|col1|col2|
+----------+----+----+
|2020-08-17|   0|   0|
|2020-08-18|   2|   1|
|2020-08-19|   0|   2|
|2020-08-20|   3|   0|
|2020-08-21|   4|   2|
|2020-08-22|   1|   3|
|2020-08-23|   2|   2|
|2020-08-24|   1|   2|
|2020-08-25|   3|   1|
+----------+----+----+
from pyspark.sql.functions import current_date, col, lit

#columns used for Window partitionBy
cols_part = ['pcol1', 'pcol2']

df_today = TEST_df.select([
    (current_date() if c == 'date' else col(c) if c in cols_part else lit(None)).alias(c)
        for c in TEST_df.columns
]).distinct()

df_new = TEST_df.union(df_today)
第1步:创建一个新的数据帧,其中一行的当前日期()为日期,为col1和col2设置为空,然后将其合并回测试日期(注意:将所有2020-08-26更改为最终代码中的
当前日期()
):

编辑:实际上,数据是分区的,每个分区应该添加一行,您可以执行以下操作:

TEST_schema = StructType([StructField("date", StringType(), True),\
                          StructField("col1", IntegerType(), True),
                          StructField("col2", IntegerType(), True)\
                          ])
TEST_data = [('2020-08-17',0,0),('2020-08-18',2,1),('2020-08-19',0,2),('2020-08-20',3,0),('2020-08-21',4,2),\
             ('2020-08-22',1,3),('2020-08-23',2,2),('2020-08-24',1,2),('2020-08-25',3,1)]
rdd3 = sc.parallelize(TEST_data)
TEST_df = sqlContext.createDataFrame(TEST_data, TEST_schema)
TEST_df = TEST_df.withColumn("date",to_date("date", 'yyyy-MM-dd'))
TEST_df.show() 

+----------+----+----+
|      date|col1|col2|
+----------+----+----+
|2020-08-17|   0|   0|
|2020-08-18|   2|   1|
|2020-08-19|   0|   2|
|2020-08-20|   3|   0|
|2020-08-21|   4|   2|
|2020-08-22|   1|   3|
|2020-08-23|   2|   2|
|2020-08-24|   1|   2|
|2020-08-25|   3|   1|
+----------+----+----+
from pyspark.sql.functions import current_date, col, lit

#columns used for Window partitionBy
cols_part = ['pcol1', 'pcol2']

df_today = TEST_df.select([
    (current_date() if c == 'date' else col(c) if c in cols_part else lit(None)).alias(c)
        for c in TEST_df.columns
]).distinct()

df_new = TEST_df.union(df_today)
步骤2:进行计算以填充上述空值:

df_new.selectExpr(
  "date", 
  "IF(date < '2020-08-26', col1, lag(IF(col1>0, col1+col2,0)) over(order by date)) as col1",
  "lag(col2,1,0) over(order by date) as col2"
).show()
+----------+----+----+
|      date|col1|col2|
+----------+----+----+
|2020-08-17|   0|   0|
|2020-08-18|   2|   0|
|2020-08-19|   0|   1|
|2020-08-20|   3|   2|
|2020-08-21|   4|   0|
|2020-08-22|   1|   2|
|2020-08-23|   2|   3|
|2020-08-24|   1|   2|
|2020-08-25|   3|   2|
|2020-08-26|   4|   1|
+----------+----+----+
df_new.selectExpr(
“日期”,
“如果(日期<'2020-08-26',col1,滞后(如果(col1>0,col1+col2,0))超过(按日期排序))作为col1”,
“滞后(col2,1,0)超过(按日期排序)为col2”
).show()
+----------+----+----+
|日期| col1 | col2|
+----------+----+----+
|2020-08-17|   0|   0|
|2020-08-18|   2|   0|
|2020-08-19|   0|   1|
|2020-08-20|   3|   2|
|2020-08-21|   4|   0|
|2020-08-22|   1|   2|
|2020-08-23|   2|   3|
|2020-08-24|   1|   2|
|2020-08-25|   3|   2|
|2020-08-26|   4|   1|
+----------+----+----+

IIUC,您可以尝试以下操作:

TEST_schema = StructType([StructField("date", StringType(), True),\
                          StructField("col1", IntegerType(), True),
                          StructField("col2", IntegerType(), True)\
                          ])
TEST_data = [('2020-08-17',0,0),('2020-08-18',2,1),('2020-08-19',0,2),('2020-08-20',3,0),('2020-08-21',4,2),\
             ('2020-08-22',1,3),('2020-08-23',2,2),('2020-08-24',1,2),('2020-08-25',3,1)]
rdd3 = sc.parallelize(TEST_data)
TEST_df = sqlContext.createDataFrame(TEST_data, TEST_schema)
TEST_df = TEST_df.withColumn("date",to_date("date", 'yyyy-MM-dd'))
TEST_df.show() 

+----------+----+----+
|      date|col1|col2|
+----------+----+----+
|2020-08-17|   0|   0|
|2020-08-18|   2|   1|
|2020-08-19|   0|   2|
|2020-08-20|   3|   0|
|2020-08-21|   4|   2|
|2020-08-22|   1|   3|
|2020-08-23|   2|   2|
|2020-08-24|   1|   2|
|2020-08-25|   3|   1|
+----------+----+----+
from pyspark.sql.functions import current_date, col, lit

#columns used for Window partitionBy
cols_part = ['pcol1', 'pcol2']

df_today = TEST_df.select([
    (current_date() if c == 'date' else col(c) if c in cols_part else lit(None)).alias(c)
        for c in TEST_df.columns
]).distinct()

df_new = TEST_df.union(df_today)
第1步:创建一个新的数据帧,其中一行的当前日期()为日期,为col1和col2设置为空,然后将其合并回测试日期(注意:将所有2020-08-26更改为最终代码中的
当前日期()
):

编辑:实际上,数据是分区的,每个分区应该添加一行,您可以执行以下操作:

TEST_schema = StructType([StructField("date", StringType(), True),\
                          StructField("col1", IntegerType(), True),
                          StructField("col2", IntegerType(), True)\
                          ])
TEST_data = [('2020-08-17',0,0),('2020-08-18',2,1),('2020-08-19',0,2),('2020-08-20',3,0),('2020-08-21',4,2),\
             ('2020-08-22',1,3),('2020-08-23',2,2),('2020-08-24',1,2),('2020-08-25',3,1)]
rdd3 = sc.parallelize(TEST_data)
TEST_df = sqlContext.createDataFrame(TEST_data, TEST_schema)
TEST_df = TEST_df.withColumn("date",to_date("date", 'yyyy-MM-dd'))
TEST_df.show() 

+----------+----+----+
|      date|col1|col2|
+----------+----+----+
|2020-08-17|   0|   0|
|2020-08-18|   2|   1|
|2020-08-19|   0|   2|
|2020-08-20|   3|   0|
|2020-08-21|   4|   2|
|2020-08-22|   1|   3|
|2020-08-23|   2|   2|
|2020-08-24|   1|   2|
|2020-08-25|   3|   1|
+----------+----+----+
from pyspark.sql.functions import current_date, col, lit

#columns used for Window partitionBy
cols_part = ['pcol1', 'pcol2']

df_today = TEST_df.select([
    (current_date() if c == 'date' else col(c) if c in cols_part else lit(None)).alias(c)
        for c in TEST_df.columns
]).distinct()

df_new = TEST_df.union(df_today)
步骤2:进行计算以填充上述空值:

df_new.selectExpr(
  "date", 
  "IF(date < '2020-08-26', col1, lag(IF(col1>0, col1+col2,0)) over(order by date)) as col1",
  "lag(col2,1,0) over(order by date) as col2"
).show()
+----------+----+----+
|      date|col1|col2|
+----------+----+----+
|2020-08-17|   0|   0|
|2020-08-18|   2|   0|
|2020-08-19|   0|   1|
|2020-08-20|   3|   2|
|2020-08-21|   4|   0|
|2020-08-22|   1|   2|
|2020-08-23|   2|   3|
|2020-08-24|   1|   2|
|2020-08-25|   3|   2|
|2020-08-26|   4|   1|
+----------+----+----+
df_new.selectExpr(
“日期”,
“如果(日期<'2020-08-26',col1,滞后(如果(col1>0,col1+col2,0))超过(按日期排序))作为col1”,
“滞后(col2,1,0)超过(按日期排序)为col2”
).show()
+----------+----+----+
|日期| col1 | col2|
+----------+----+----+
|2020-08-17|   0|   0|
|2020-08-18|   2|   0|
|2020-08-19|   0|   1|
|2020-08-20|   3|   2|
|2020-08-21|   4|   0|
|2020-08-22|   1|   2|
|2020-08-23|   2|   3|
|2020-08-24|   1|   2|
|2020-08-25|   3|   2|
|2020-08-26|   4|   1|
+----------+----+----+

谢谢,如果我有20个类似的计算列怎么办?使用这种方法是没有效率的,正确吗?而且也有风险:(这些列的计算结果是什么,如果它们进行相同的计算,那么我们很可能可以使用列表理解来迭代。在bigdata任务中,执行
转置
通常不是一个好主意。您可以动态创建许多内容,例如:
df_new=TEST_df.union(spark.sql(f“select current_Date(),{,'.join(20*['null']}”)
添加当前日期为()的行plus
20
nulls。编写一个函数来定义相同的逻辑以供重用。复杂的逻辑更容易在列级实现,如果每行都有不同的逻辑,这将是一个混乱。@hellotherebj,如果它回答了您的问题,您介意接受答案吗?谢谢,如果我有类似于20ish的计算列怎么办?它不会有效使用这种方法进行耳鼻喉科手术是正确的,也是有风险的:(这些列的计算结果是什么,如果它们进行相同的计算,那么我们很可能可以使用列表理解来迭代。在bigdata任务中,执行
转置
通常不是一个好主意。您可以动态创建许多内容,例如:
df_new=TEST_df.union(spark.sql(f“select current_Date(),{','.join(20*['null']}”)
添加一行当前日期()加上
20
null。编写一个函数来定义相同的逻辑以供重用。复杂的逻辑更容易在列级实现,如果每行有不同的逻辑,这将是一个混乱。@hellotherebj,如果它回答了您的问题,您介意接受答案吗?