Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何基于每个分区重新索引数据帧_Python_Pyspark_Apache Spark Sql_Pyspark Sql - Fatal编程技术网

Python 如何基于每个分区重新索引数据帧

Python 如何基于每个分区重新索引数据帧,python,pyspark,apache-spark-sql,pyspark-sql,Python,Pyspark,Apache Spark Sql,Pyspark Sql,假设我有pyspark创建的以下数据帧 id date deleted 1 2019-02-07 true 1 2019-02-04 false 2 2019-02-01 true 3 2019-02-08 false 3 2019-02-06 true 我想从最早的日期到现在(比如2019-02-09),每天重新编制该表的索引,最早的日期基于每个id,例如,对于id 1,最早的日期是2019-02-04,对于id

假设我有pyspark创建的以下数据帧

id  date         deleted
1   2019-02-07     true
1   2019-02-04     false
2   2019-02-01     true
3   2019-02-08     false
3   2019-02-06     true
我想从最早的日期到现在(比如2019-02-09),每天重新编制该表的索引,最早的日期基于每个id,例如,对于id 1,最早的日期是2019-02-04,对于id 3,最早的日期是2019-02-06。预期结果是:

id  date         deleted
1   2019-02-04     false
1   2019-02-05     null
1   2019-02-06     null
1   2019-02-07     true
1   2019-02-08     null
1   2019-02-09     null

2   2019-02-01     true
2   2019-02-02     null
      ...
2   2019-02-09     null

3   2019-02-06     true
3   2019-02-07     null
3   2019-02-08     false
3   2019-02-09     null
我知道如何根据所有id(即2019-02-01)为最早的日期执行此操作,然后只需为每个id构建一个包含2019-02-01至2019-02-09所有日期的数据框(交叉连接),然后左连接原始数据框。这种方法的问题是,如果有一个日期,比如1980-01-01,那么重新索引将为所有ID填充从1980-01-01到现在的所有数据,这是没有意义的,并且将影响此数据帧上以下ETL的性能


对于基于每个分区的最早日期,没有找到一个很好的方法。

假设原始数据帧被称为
df
,并且
date
列的类型确实是
DateType

import pyspark.sql.functions as F
from pyspark.sql.types import DateType, ArrayType
import datetime

# create a UDF to create a range of dates from a start
# date until today
def construct_date_range(start_date):
    ndays = (datetime.datetime.today() - start_date).days
    return reversed([base - datetime.timedelta(days=x) for x in range(0, ndays+1)])
date_range_udf = F.udf(construct_date_range, ArrayType(DateType()))

# find the first date for each id, and create a record for
# all dates since the first
id_dates = (
    df
    .groupBy('id')
    .agg(F.min('date').alias('min_date'))
    .withColumn('date_arr', construct_date_range('min_date'))
    .select('id', F.explode('date_arr').alias('date'))
)

result = id_dates.join(df, on=['id','date'], how='left')

基于@abeboparebop的解决方案,我修复了一些格式问题,并使其工作如下:

import pyspark.sql.functions as F
from pyspark.sql.types import DateType, ArrayType
import pandas as pd

from datetime import datetime

import pandas as pd

SYDNEY_TZ = "Australia/Sydney"

def _utc_now():
    return datetime.utcnow()

def _current_datetime_index(timezone=SYDNEY_TZ):
    return pd.DatetimeIndex([_utc_now()]).tz_localize("UTC").tz_convert(timezone).tz_localize(None)


def current_datetime(timezone=SYDNEY_TZ):
    return _current_datetime_index(timezone).to_pydatetime()[0]

def generate_date_list(date_from, date_to=None):
    if date_to is None:
        date_to = current_datetime()
    return pd.date_range(date_from.date(), date_to.date(), freq="D").date.tolist()


def construct_date_range(start_date):
    return generate_date_list(pd.to_datetime(start_date))


date_range_udf = F.udf(construct_date_range, ArrayType(DateType()))


id_dates = (
    given_df
    .groupBy('id')
    .agg(F.min('date').alias('min_date'))
    .withColumn('date_arr', date_range_udf(F.col('min_date')))
    .select('id', F.explode('date_arr').alias('date'))
)

result = id_dates.join(given_df, on=['id', 'date'], how='left')

谢谢你的回答,我认为解决方案是正确的,只是发现了一些格式问题<代码>不支持的操作数类型-:“datetime.datetime”和“str”。基于此,我成功了。