【问题标题】:Pandas cannot read parquet files created in PySparkPandas 无法读取在 PySpark 中创建的镶木地板文件
【发布时间】:2019-06-09 15:19:43
【问题描述】:

我正在通过以下方式从 Spark DataFrame 编写镶木地板文件:

df.write.parquet("path/myfile.parquet", mode = "overwrite", compression="gzip")

这将创建一个包含多个文件的文件夹。

当我尝试将其读入 pandas 时,我收到以下错误,具体取决于我使用的解析器:

import pandas as pd
df = pd.read_parquet("path/myfile.parquet", engine="pyarrow")

PyArrow:

文件“pyarrow\error.pxi”,第 83 行,在 pyarrow.lib.check_status 中

ArrowIOError:镶木地板文件无效。损坏的页脚。

快速镶木地板:

文件“C:\Program Files\Anaconda3\lib\site-packages\fastparquet\util.py”,第 38 行,在 default_open 返回打开(f,模式)

PermissionError: [Errno 13] Permission denied: 'path/myfile.parquet'

我正在使用以下版本:

  • Spark 2.4.0
  • 熊猫 0.23.4
  • pyarrow 0.10.0
  • fastparquet 0.2.1

我尝试了 gzip 以及 snappy 压缩。两者都不起作用。我当然确保我将文件放在 Python 有权读取/写入的位置。

如果有人能够重现此错误,那已经很有帮助了。

【问题讨论】:

    标签: python pandas apache-spark pyspark parquet


    【解决方案1】:

    问题在于 Spark 由于其分布式特性而对文件进行分区(每个执行程序在接收文件名的目录中写入一个文件)。这不是 Pandas 支持的东西,它需要一个文件,而不是路径。

    您可以通过多种方式规避此问题:

    • 使用替代实用程序读取文件,例如pyarrow.parquet.ParquetDataset,然后将其转换为 Pandas(我没有测试此代码)。

        arrow_dataset = pyarrow.parquet.ParquetDataset('path/myfile.parquet')
        arrow_table = arrow_dataset.read()
        pandas_df = arrow_table.to_pandas()
      
    • 另一种方法是分别读取单独的片段,然后将它们连接起来,正如这个答案所暗示的那样:Read multiple parquet files in a folder and write to single csv file using python

    【讨论】:

    • 感谢您的回答。似乎读取单个文件(您的第二个要点)有效。但是,第一件事不起作用 - 看起来 pyarrow 无法处理 PySpark 的页脚(请参阅有问题的错误消息)
    • @Thomas,很遗憾,我不确定页脚问题。
    • 或者您可以尝试在数据帧上调用 coalesce:coalesce(1),以便将所有部分文件合并到一个文件中,然后从单个文件而不是文件目录中读取?
    • @OmkarNeogi:这只有在你是编写文件的人的情况下才有可能,而不是你从其他人那里收到的......
    • 我更新了它以使用实际的 API,即您创建一个数据集,将其转换为表,然后转换为 Pandas DataFrame。
    【解决方案2】:

    如果parquet文件是用spark创建的,(所以它是一个目录)将其导入pandas使用

    from pyarrow.parquet import ParquetDataset
    
    dataset = ParquetDataset("file.parquet")
    table = dataset.read()
    df = table.to_pandas()
    

    【讨论】:

      【解决方案3】:

      由于即使使用较新的 pandas 版本,这似乎仍然是一个问题,所以我编写了一些函数来规避这个问题,作为更大的 pyspark 助手库的一部分:

      import pandas as pd
      import datetime
      
      def read_parquet_folder_as_pandas(path, verbosity=1):
        files = [f for f in os.listdir(path) if f.endswith("parquet")]
      
        if verbosity > 0:
          print("{} parquet files found. Beginning reading...".format(len(files)), end="")
          start = datetime.datetime.now()
      
        df_list = [pd.read_parquet(os.path.join(path, f)) for f in files]
        df = pd.concat(df_list, ignore_index=True)
      
        if verbosity > 0:
          end = datetime.datetime.now()
          print(" Finished. Took {}".format(end-start))
        return df
      
      
      def read_parquet_as_pandas(path, verbosity=1):
        """Workaround for pandas not being able to read folder-style parquet files.
        """
        if os.path.isdir(path):
          if verbosity>1: print("Parquet file is actually folder.")
          return read_parquet_folder_as_pandas(path, verbosity)
        else:
          return pd.read_parquet(path)
      

      这假设parquet“file”中的相关文件,实际上是一个文件夹,以“.parquet”结尾。这适用于由 databricks 导出的 parquet 文件,也可以与其他文件一起使用(未经测试,对 cme​​ts 中的反馈感到满意)。

      如果事先不知道是不是文件夹,可以使用read_parquet_as_pandas()函数。

      【讨论】:

        猜你喜欢
        • 2021-10-14
        • 2021-11-10
        • 2022-06-16
        • 2019-08-04
        • 2018-08-13
        • 1970-01-01
        • 2021-03-19
        • 2021-04-24
        • 1970-01-01
        相关资源
        最近更新 更多