Pandas 无法读取在 PySpark 中创建的镶木地板文件
Pandas cannot read parquet files created in PySpark
我正在通过以下方式从 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:
File "pyarrow\error.pxi", line 83, in pyarrow.lib.check_status
ArrowIOError: Invalid parquet file. Corrupt footer.
fastparquet:
File "C:\Program Files\Anaconda3\lib\site-packages\fastparquet\util.py", line 38, in default_open
return open(f, mode)
PermissionError: [Errno 13] Permission denied: 'path/myfile.parquet'
我正在使用以下版本:
- Spark 2.4.0
- Pandas 0.23.4
- pyarrow 0.10.0
- 快速镶木地板 0.2.1
我尝试了 gzip 和 snappy 压缩。两者都不起作用。我当然确保文件位于 Python 有权访问 read/write.
的位置
如果有人能够重现此错误,那将会有所帮助。
问题是 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()
另一种方法是分别读取单独的片段,然后将它们连接起来,正如这个答案所建议的:
因为即使使用较新的 pandas 版本,这似乎仍然是一个问题,所以我编写了一些函数来规避此问题,作为更大的 pyspark 助手库的一部分:
import pandas as pd
import datetime
import os
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“文件”中的相关文件,实际上是一个文件夹,以“.parquet”结尾。这适用于由数据块导出的镶木地板文件,也可能适用于其他文件(未经测试,对评论中的反馈感到高兴)。
如果事先不知道是不是文件夹,可以使用函数read_parquet_as_pandas()
。
如果 parquet 文件是用 spark 创建的,(所以它是一个目录)将其导入 pandas 使用
from pyarrow.parquet import ParquetDataset
dataset = ParquetDataset("file.parquet")
table = dataset.read()
df = table.to_pandas()
我正在通过以下方式从 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:
File "pyarrow\error.pxi", line 83, in pyarrow.lib.check_status
ArrowIOError: Invalid parquet file. Corrupt footer.
fastparquet:
File "C:\Program Files\Anaconda3\lib\site-packages\fastparquet\util.py", line 38, in default_open return open(f, mode)
PermissionError: [Errno 13] Permission denied: 'path/myfile.parquet'
我正在使用以下版本:
- Spark 2.4.0
- Pandas 0.23.4
- pyarrow 0.10.0
- 快速镶木地板 0.2.1
我尝试了 gzip 和 snappy 压缩。两者都不起作用。我当然确保文件位于 Python 有权访问 read/write.
的位置如果有人能够重现此错误,那将会有所帮助。
问题是 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()
另一种方法是分别读取单独的片段,然后将它们连接起来,正如这个答案所建议的:
因为即使使用较新的 pandas 版本,这似乎仍然是一个问题,所以我编写了一些函数来规避此问题,作为更大的 pyspark 助手库的一部分:
import pandas as pd
import datetime
import os
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“文件”中的相关文件,实际上是一个文件夹,以“.parquet”结尾。这适用于由数据块导出的镶木地板文件,也可能适用于其他文件(未经测试,对评论中的反馈感到高兴)。
如果事先不知道是不是文件夹,可以使用函数read_parquet_as_pandas()
。
如果 parquet 文件是用 spark 创建的,(所以它是一个目录)将其导入 pandas 使用
from pyarrow.parquet import ParquetDataset
dataset = ParquetDataset("file.parquet")
table = dataset.read()
df = table.to_pandas()