我有一个如下数据框:
+----+--------+--------+------+
| id | value1 | value2 | flag |
+----+--------+--------+------+
| 1 | 7000 | 30 | 0 |
| 2 | 0 | 9 | 0 |
| 3 | 23627 | 17 | 1 |
| 4 | 8373 | 23 | 0 |
| 5 | -0.5 | 4 | 1 |
+----+--------+--------+------+
我要运行以下条件-
1.如果value大于0,我希望前一行为value2
2.如果value等于0,我想要上一行和下一行的平均值2
3.如果值小于0,则为NULL
所以我写了下面的代码-
df = df.withColumn('value2',when(col(value1)>0,lag(col(value2))).when(col(value1)==0,\
(lag(col(value2))+lead(col(value2)))/2.0).otherwise(None))
我想要的是在获取上一行和下一行的值时应具有更新后的值,如下所示。应该按照找到它们的顺序进行操作,首先对id-1进行更新,然后对id-2进行更新,以此类推。
+----+--------+--------+------+
| id | value1 | value2 | flag |
+----+--------+--------+------+
| 1 | 7000 | null | 0 |
| 2 | 0 | 8.5 | 0 |
| 3 | 23627 | 8.5 | 1 |
| 4 | 8373 | 8.5 | 0 |
| 5 | -0.5 | null | 1 |
+----+--------+--------+------+
我尝试通过在何时重新分配数据帧时给id == 1来进行操作,然后在操作时再次使用列进行操作。
df = df.withColumn('value2',when((col(id)==1)&(col(value1)>0,lag(col(value2)))
\.when((col(id)==1)&col(value1)==0,(lag(col(value2))+lead(col(value2)))/2.0)\
.when((col(id)==1)&col(col(value1)<0,None).otherwise(col(value2))
此后,我将获取更新的列值,如果再次对id == 2进行相同的操作,则可以获取更新的值。但是我当然不能为每个id都这样做。我该如何实现?
答案 0 :(得分:0)
DiffUtil
“ final_table”上方将包含您期望的字段。
答案 1 :(得分:0)
我认为完全没有循环执行此操作将很复杂。但是您可以使用udf将工作分散到熊猫的不同执行者和子集中。为了使其正常工作,必须有足够的断点(即,值小于0且您要插入NULL的数据点)。
进口:
from pyspark.sql import Window
from pyspark.sql.functions import last
from pyspark.sql.functions import pandas_udf
from pyspark.sql.functions import PandasUDFType
import pandas as pd
import numpy as np
from pyspark.sql.functions import col, lit, when
输入数据:
df = spark.createDataFrame([[ 1, 7000.0, 30.0 ], [ 2, 0.0, 9.0], [3, 23628.0, 17.0], [4, 8373.0, 23.0], [5, -0.5, 4.0]], [ 'id', 'value1', 'value2' ]).cache()
添加下一个值2并在值小于0时设置断点:
dfwithnextvalue = df.alias("a").join(df.alias("b"), col("a.id") == col("b.id") - lit(1), 'left').select("a.*", col("b.value2").alias("nextvalue"))
dfstartnew = dfwithnextvalue.withColumn("startnew", when(col("value1") < lit(0), col("id")).otherwise(lit(None)))\
.withColumn("startnew", when(col("id") == lit(1), lit(1)).otherwise(col("startnew")))
window = Window.orderBy('id')
rolled = last(col('startnew'), ignorenulls=True).over(window)
dfstartnewrolled = dfstartnew.withColumn("startnew", rolled)
现在,我们可以按startnew
列进行分组并处理大熊猫中的每一片。我的熊猫知识不是很好,但这似乎行得通:
@pandas_udf("id long, value1 double, value2 double", PandasUDFType.GROUPED_MAP)
def loopdata(df):
df = df.set_index('id').sort_index()
for i in range(0, len(df.index)):
if i == 0:
df.loc[df.index[0], 'value2'] = np.nan
elif df.loc[df.index[i], 'value1'] < 0:
df.loc[df.index[i], 'value2'] = np.nan
elif df.loc[df.index[i], 'value1'] > 0:
df.loc[df.index[i], 'value2'] = df.loc[df.index[i-1], 'value2']
else:
nextvalue = df.loc[df.index[i], 'nextvalue']
if pd.isna(nextvalue):
nextvalue = 0
prevvalue = df.loc[df.index[i-1], 'value2']
if pd.isna(prevvalue):
prevvalue = 0
df.loc[df.index[i], 'value2'] = (nextvalue + prevvalue)/2.0
df = df.drop(columns=['nextvalue', 'startnew'])
df = df.reset_index()
return df
现在您可以计算出结果:
dfstartnewrolled.groupBy("startnew").apply(loopdata)