熊猫无法读取在PySpark中创建的实木复合地板文件

时间:2019-01-15 15:20:03

标签: python pandas apache-spark pyspark parquet

我正在通过以下方式从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.lib.check_status中的文件“ pyarrow \ error.pxi”,第83行

     

ArrowIOError:无效的实木复合地板文件。页脚已损坏。

快速镶木地板

  

文件“ C:\ Program Files \ Anaconda3 \ lib \ site-packages \ fastparquet \ util.py”,行38,在default_open中       返回open(f,mode)

     

PermissionError:[Errno 13]权限被拒绝:'path / myfile.parquet'

我正在使用以下版本:

  • 火花2.4.0
  • 熊猫0.23.4
  • 金字塔0.10.0
  • fastparquet 0.2.1

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

如果有人能够重现此错误,这将有所帮助。

3 个答案:

答案 0 :(得分:2)

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

您可以通过不同的方式规避此问题:

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

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

答案 1 :(得分:2)

如果镶木地板文件是用spark创建的(因此是一个目录),则将其导入到大熊猫中使用

from pyarrow.parquet import ParquetDataset

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

答案 2 :(得分:0)

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

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”结尾。此方法适用于数据砖导出的镶木文件,也可以与其他文件一起使用(未经测试,对评论中的反馈感到高兴)。

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