求助:将实现行列转换逻辑的SAS代码迁移为PySpark代码
SAS代码转PySpark的正确实现方案
原SAS代码及逻辑
首先看需要转换的SAS代码:
data work2(drop=i K); set work1; ARRAY History(36) $ History_1-History_36; array History_new(36)$ History_new1-History_new36; if INTCK('MONTH',DateReported,MIS_DATE)>=0 then VINTAGE_DateReported= INTCK('MONTH',DateReported,MIS_DATE)+1; else VINTAGE_DateReported=1; I=0; do k=VINTAGE_DateReported to 36; I+1; History_new(k)=History(I); END; run;
原代码核心逻辑:
- 基于
work1生成work2,丢弃循环变量i和K - 定义两个长度为36的字符数组:
History对应History_1至History_36,History_new对应History_new1至History_new36 - 计算
VINTAGE_DateReported:若DateReported到MIS_DATE的月份差≥0,则取「月份差+1」,否则设为1 - 循环赋值:将
History数组的前N个元素(N=36-VINTAGE_DateReported+1),依次赋值给History_new数组从VINTAGE_DateReported到36的位置,未赋值的History_new元素保持缺失
你尝试的代码问题
你写的PySpark代码存在多处语法错误与逻辑问题:
- 在
lambda表达式中使用collect()属于错误操作:collect()是Action算子,不能在转换算子(如map)中调用,会触发不必要的计算且破坏分布式逻辑 - 列名拼接与数组访问的语法不符合PySpark规范
- 错误混用了DataFrame与RDD的操作方式
正确的PySpark实现方案
以下是对应逻辑的PySpark代码实现:
from pyspark.sql import functions as F from pyspark.sql.types import IntegerType # 1. 计算VINTAGE_DateReported列 work1 = work1.withColumn( "VINTAGE_DateReported", F.when( # 匹配SAS INTCK('MONTH', start, end)的逻辑,取月份差的整数部分 F.months_between(F.col("MIS_DATE"), F.col("DateReported")) >= 0, F.floor(F.months_between(F.col("MIS_DATE"), F.col("DateReported"))).cast(IntegerType()) + 1 ).otherwise(1) ) # 2. 循环生成每个History_new列 for k in range(1, 37): # 计算对应的History列索引:当k >= VINTAGE_DateReported时,I = k - VINTAGE_DateReported + 1 work1 = work1.withColumn( f"History_new{k}", F.when( F.col("VINTAGE_DateReported") <= k, F.col(f"History_{k - F.col('VINTAGE_DateReported') + 1}") ).otherwise(F.lit(None)) # 未赋值的位置保持缺失,对应SAS默认逻辑 ) # 3. 生成最终数据集work2,丢弃临时计算列VINTAGE_DateReported(对应SAS的drop=i K) work2 = work1.drop("VINTAGE_DateReported")
代码说明
- 使用PySpark的
months_between函数替代SAS的INTCK('MONTH'),通过floor取整数部分匹配SAS的整数月份差逻辑 - 循环遍历每个
History_new列,通过when条件判断实现SAS的循环赋值逻辑 - 最终丢弃临时计算的
VINTAGE_DateReported列,对应SAS中丢弃循环变量的操作
内容的提问来源于stack exchange,提问作者S K SINGH
相关产品推荐
相关产品推荐

