繁体   English   中英

PySpark:如何基于其他行值更改行+列的值

[英]PySpark: How do I change the value of a row+column based on the value of other row values

我有一个这样的数据框...

+----------+-----+
|      date|price|
+----------+-----+
|2019-01-01|   25|
|2019-01-02|   22|
|2019-01-03|   20|
|2019-01-04|   -5|
|2019-01-05|   -1|
|2019-01-06|   -2|
|2019-01-07|    5|
|2019-01-08|  -11|
+----------+-----+

我想基于一种逻辑来创建一个新列,该逻辑需要回顾其他行-而不仅仅是同一行的列值

我正在尝试一些UDF,但它采用了列的相应行值。 我不知道如何查看其他行...

与示例:我想创建一个新列“ newprice”-这将是这样的...

+----------+-----+----------+
|      date|price|new price
+----------+-----+----------+
|2019-01-01|   25| 25
|2019-01-02|   22| 22
|2019-01-03|   20| 20
|2019-01-04|   -5| 20
|2019-01-05|   -1| 20
|2019-01-06|   -2| 20
|2019-01-07|    5| 5
|2019-01-08|  -11| 5
+----------+-----+-----------+

基本上,新列值中的每一行都不基于相应行的值,而是另一行的值...

逻辑:如果价格为负数,则回顾前几天,如果该日为正值-接受它或再返回一天直到有正值可用...

    dateprice = [('2019-01-01',25),('2019-01-02',22),('2019-01-03',20),('2019-01-04', -5),\
     ('2019-01-05',-1),('2019-01-06',-2),('2019-01-07',5),('2019-01-08', -11)]

   dataDF = sqlContext.createDataFrame(dateprice, ('date', 'price'))



任何帮助将不胜感激。

首先用price列填充new priceprice列,但用null替换负值。 然后,您可以使用pyspark中使用先前已知的好值填写空值中显示的技术来获取最后一个非空值,在这种情况下,该值将为最后一个正值。

例如:

from pyspark.sql.functions import col, last, when
from pyspark.sql import Window

w = Window.orderBy("date").rowsBetween(Window.unboundedPreceding, Window.currentRow)

dataDF.withColumn("new_price", when(col("price") >= 0, col("price")))\
    .withColumn(
        "new_price",
        last('new_price', True).over(w)
    )\
    .show()
#+----------+-----+---------+
#|      date|price|new_price|
#+----------+-----+---------+
#|2019-01-01|   25|       25|
#|2019-01-02|   22|       22|
#|2019-01-03|   20|       20|
#|2019-01-04|   -5|       20|
#|2019-01-05|   -1|       20|
#|2019-01-06|   -2|       20|
#|2019-01-07|    5|        5|
#|2019-01-08|  -11|        5|
#+----------+-----+---------+

在这里,我已经采取了这样的事实优势, when返回null默认情况下,如果条件不符合,不otherwise指定。

我使用Spark SQL尝试了这一方法。 让我分两部分解释我的解决方案,

首先,当价格为负数时,我们可以获取价格为正数的最近日期,否则我们可以填充价格本身,如下所示,

spark.sql("""
select *,
case when price < 0 then
max(lag(case when price < 0 then null else date end) over(order by date))
over(order by date rows between unbounded preceding and current row)
else price end as price_or_date 
from dataset
""").show()

输出:

+----------+-----+-------------+
|      date|price|price_or_date|
+----------+-----+-------------+
|2019-01-01|   25|           25|
|2019-01-02|   22|           22|
|2019-01-03|   20|           20|
|2019-01-04|   -5|   2019-01-03|
|2019-01-05|   -1|   2019-01-03|
|2019-01-06|   -2|   2019-01-03|
|2019-01-07|    5|            5|
|2019-01-08|  -11|   2019-01-07|
+----------+-----+-------------+

其次,您可以使用date和此派生列对同一数据集进行left join 因此,现在在price_or_date列中带有价格的price_or_date将显示为null 最后,我们可以对它们执行简单的coalesce

结合它们,我们可以实现以下所示的最终查询,以生成所需的输出,

spark.sql("""
select 
   a.date
 , a.price
 , coalesce(b.price, a.price) as new_price
from
(
select *,
case when price < 0 then
max(lag(case when price < 0 then null else date end) over(order by date))
over(order by date rows between unbounded preceding and current row)
else price end as price_or_date 
from dataset
) a
left join dataset b
on a.price_or_date = b.date 
order by a.date""").show()

输出:

+----------+-----+---------+
|      date|price|new_price|
+----------+-----+---------+
|2019-01-01|   25|       25|
|2019-01-02|   22|       22|
|2019-01-03|   20|       20|
|2019-01-04|   -5|       20|
|2019-01-05|   -1|       20|
|2019-01-06|   -2|       20|
|2019-01-07|    5|        5|
|2019-01-08|  -11|        5|
+----------+-----+---------+

希望这可以帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM