Python 随着pyspark数据帧变小,toPandas()是否会加快速度?

Python 随着pyspark数据帧变小,toPandas()是否会加快速度?,python,pandas,pyspark,Python,Pandas,Pyspark,我想我会问这个问题。我发现了一种聪明的方法来减小PySpark数据帧的大小并将其转换为Pandas,我只是想知道,随着PySpark数据帧的大小变小,toPandas函数是否会变得更快?下面是一些代码: window = Window.partitionBy(F.lit('A')).orderBy(F.lit('A')) eps_tfs = {} while True: pdf = toPandas(conn.select(F.col('*')).where(F.col('row_nu

我想我会问这个问题。我发现了一种聪明的方法来减小PySpark数据帧的大小并将其转换为Pandas,我只是想知道,随着PySpark数据帧的大小变小,toPandas函数是否会变得更快?下面是一些代码:

window = Window.partitionBy(F.lit('A')).orderBy(F.lit('A'))

eps_tfs = {}
while True:
    pdf = toPandas(conn.select(F.col('*')).where(F.col('row_number') <= 2500))
    n = len(pdf)
    trigger = 0
    for u in pdf['features']:
        indices = [i for i, x in enumerate(u) if x == 1.0]
        for idx in range(len(eps_columns)):
            if idx in indices:
                try:
                    eps_tfs[eps_columns[idx]].append(True)
                except:
                    eps_tfs[eps_columns[idx]] = [True]
            else:
                try:
                    eps_tfs[eps_columns[idx]].append(False)
                except:
                    eps_tfs[eps_columns[idx]] = [False]
    full_view = full_view.append(pd.concat([pdf, pd.DataFrame(eps_tfs)], axis=1))
    conn = conn.select(F.col('*')).where(F.col('row_number') > 2500)
    conn = conn.drop("row_number")
    conn = conn.select(F.col('*'), F.row_number().over(window).alias('row_number'))
    eps_tfs = {}
    del pdf
    if n < 2500:
        break
有没有更好的方法来实现这一点?

是ToPandas的源代码

首先,是的,如果pyspark数据帧变小,toPandas会更快,它的味道与sdf.collect相似 区别在于ToPandas返回pdf和collect返回列表。 从源代码pdf=pd.DataFrame.from_recordsself.collect中可以看到,columns=self.columns pdf是从列表中的pd.DataFrame.from_记录生成的

因此,如果您的sdf较小,则需要通过网络传输的数据较小,并且可以使用驱动程序的CPU记录较少的数据

第二个代码的设计是不同的,sdf是分布式的,代码调用Mappartition,因此所有工作人员从数据子集生成一个Pandas数据帧,然后调用collect,现在通过网络传输的所有Pandas数据帧被带到驱动程序。然后,代码调用pd.concat将所有数据帧连接在一起

好处是:

在转换为Pandas DataFrame时,所有工作人员并行处理一小部分数据,这比将所有数据带到驱动程序并烧掉驱动程序的CPU以将大数据转换为Pandas要好得多。 正在进行重新分区,这意味着如果您的数据集很大,并且您的分区数很低,则每个分区上的数据都会很大,并且toPandas在序列化程序的OOM上会失败,并且收集数据的速度也非常慢 缺点是:

现在,当您收集时,您并不是在收集本机sdf数据,而是一个附加了更多元数据且通常更大的数据帧,这意味着对象的总大小更大 pd.concat是慢lol,但可能仍然比从_记录更好
因此,没有普遍的结论说哪种方法更好,而是明智地选择使用哪种工具。就像在这个问题中一样,toPandas可能比小型sdf更快,但对于大型sdf,代码片段肯定工作得更好。

我会在这里提出不同的问题-pandas是否比pyspark更适合您的用例?如果是,为什么不在pandas中执行所有操作?如果不是,为什么转换?我认为toPandas的源代码应该是:
def _map_to_pandas(rdds):
    """ Needs to be here due to pickling issues """
    return [pd.DataFrame(list(rdds))]

def toPandas(df, n_partitions=None):
    """
    Returns the contents of `df` as a local `pandas.DataFrame` in a speedy fashion. The DataFrame is
    repartitioned if `n_partitions` is passed.
    :param df:              pyspark.sql.DataFrame
    :param n_partitions:    int or None
    :return:                pandas.DataFrame
    """
    if n_partitions is not None: df = df.repartition(n_partitions)
    df_pand = df.rdd.mapPartitions(_map_to_pandas).collect()
    df_pand = pd.concat(df_pand)
    df_pand.columns = df.columns
    return df_pand