A data engineer is implementing a Pandas UDF that computes a rolling 7-day weighted moving average of revenue for each store_id partition. The function requires access to multiple rows within a group simultaneously. The engineer writes the following code:
``python
from pyspark.sql.functions import pandas_udf
from pyspark.sql import Window
import pandas as pd
@pandas_udf('double')
def weighted_moving_avg(revenue: pd.Series) -> pd.Series:
return revenue.rolling(window=7, min_periods=1).mean()
result_df = df.withColumn(
'wma_revenue',
weighted_moving_avg(col('revenue')).over(
Window.partitionBy('store_id').orderBy('sale_date')
)
)
`
When this code runs, it raises: AnalysisException: Pandas UDF does not support 'over' with a Window spec`. What is the correct approach to implement this grouped rolling calculation using Pandas UDFs?
Show answer & explanation
Correct answer: A
WHY A: The correct pattern for applying group-level Pandas operations (like rolling windows per partition) is applyInPandas (the modern equivalent of GROUPED_MAP Pandas UDF). The function receives the entire Pandas DataFrame for each store_id group, allowing full Pandas rolling/window operations within the group, and returns a Pandas DataFrame. This is the idiomatic PySpark pattern for partition-level operations that require access to multiple rows simultaneously. WHY NOT B: SCALAR_ITER UDFs receive an iterator of batches for memory efficiency with scalar transformations — they do not correspond to partition groups and do not enable .over() window operations. WHY NOT C: Scalar Pandas UDFs (SCALAR type) do not support .over() window expressions, regardless of the frame specification. The AnalysisException is not resolved by changing the frame bounds. WHY NOT D: Standard Python UDFs also do not support .over() window expressions with grouping operations that require cross-row access. A standard row-at-a-time UDF cannot compute a rolling average because it receives only one row at a time. WHY NOT E: Collecting 500 million+ rows to the driver via toPandas() is an OOM anti-pattern. applyInPandas achieves the same result distributedly without moving data to the driver.