Pandas:如何从Parquet文件中读取前n行?

59

我有一个parquet文件,想要将文件中的前n行读取到pandas数据帧中。我尝试过:

df = pd.read_parquet(path= 'filepath', nrows = 10)

它没有起作用并且给了我一个错误:

TypeError: read_table() got an unexpected keyword argument 'nrows'
我确实尝试了skiprows参数,但仍然出现相同的错误。或者,我可以读取完整的Parquet文件并过滤前n行,但这将需要更多的计算,而我想避免这种情况。有没有其他方法可以实现?

现在可以使用PyArrow作为后端,实现Parquet文件的部分逐行读取,如此处所示:https://dev59.com/01QJ5IYBdhLWcg3wYUxO#69888274 - mirekphd
7个回答

63

被接受的答案已经过时。现在可以将Parquet文件的前几行读入pandas,尽管有点混乱且依赖于后端。

要使用PyArrow作为后端进行阅读,请按以下步骤操作:

from pyarrow.parquet import ParquetFile
import pyarrow as pa 

pf = ParquetFile('file_name.pq') 
first_ten_rows = next(pf.iter_batches(batch_size = 10)) 
df = pa.Table.from_batches([first_ten_rows]).to_pandas() 

batch_size = 10这一行改为与您想要读取的行数匹配的值。


而且它也非常快(对于1百万行x 2千列,只需10秒钟)。 - mirekphd
6
我们可以读取随机行吗? - ashwin agrawal
那S3呢? - jtlz2
6
@DavidKaftan,您能够选择特定的行进行阅读吗?例如:从一个非常大的 Parquet 文件中,我只想阅读索引为 13673、14762 和 68712 的行。您会如何操作? - Basj
您可以使用AWS SDK for pandas (之前称为AWS data-wrangler)中的S3 Select执行此操作和许多其他类似于SQL的操作。请参见下面的答案。 - Manuel Montoya

30

在探索并与pandas开发团队联系后,得出结论:pandas不支持在读取parquet文件时使用nrowsskiprows参数。

原因是pandas使用pyarrowfastparquet parquet引擎处理parquet文件,而pyarrow不支持部分读取文件或跳过行来读取文件(不确定fastparquet是否支持)。以下是在pandas github上讨论此问题的链接。

https://github.com/pandas-dev/pandas/issues/24511


6

使用DuckDB查询Parquet

为了提供另一种视角,如果您熟悉SQL,可以考虑使用DuckDB。例如:

import duckdb
nrows = 10
file_path = 'path/to/data/parquet_file.parquet'
df = duckdb.query(f'SELECT * FROM "{file_path}" LIMIT {nrows};').df()

如果您正在使用分区parquet,上述结果将不包括任何分区列,因为该信息未存储在较低级别的文件中。相反,您应该将顶层文件夹标识为分区parquet数据集,并使用DuckDB连接器进行注册:

import duckdb
import pyarrow.dataset as ds
nrows = 10
dataset = ds.dataset('path/to/data', 
                     format='parquet',
                     partitioning='hive')
con = duckdb.connect()
con.register('data_table_name', dataset)
df = con.execute(f"SELECT * FROM data_table_name LIMIT {nrows};").df()

您可以使用连接器注册多个数据集,以便进行更复杂的查询。我发现DuckDB使得在处理Parquet文件时更加方便,特别是在尝试在多个Parquet数据集之间进行JOIN操作时。您可以通过conda install python-duckdbpip install duckdb来安装它。


3
使用 pyarrow 数据集扫描器:
import pyarrow as pa

n = 10
src_path = "/parquet/path"
df = pa.dataset.dataset(src_path).scanner().head(n).to_pandas()

2

对我来说,最直接的选择似乎是使用 dask 库。

import dask.dataframe as dd
df = dd.read_parquet(path= 'filepath').head(10)

这是最好的答案! - wisdom_of_wombats

0

作为替代方案,您可以使用S3 Select功能,该功能来自AWS SDK for pandas,正如Abdel Jaidi在此答案中提出的建议

pip install awswrangler

import awswrangler as wr

df = wr.s3.select_query(
        sql="SELECT * FROM s3object s limit 5",
        path="s3://filepath",
        input_serialization="Parquet",
        input_serialization_params={},
        use_threads=True,
)

数据可能不在S3上。 - LudvigH
数据可能不在S3上。 - undefined
虽然这看起来是一个很好的方法,但是对于具有大块大小的Parquet文件来说,很遗憾它不起作用。 - undefined

-2

Parquet文件是列存储格式,专门设计用于...因此加载整个文件才能访问一行数据是正常的。


4
是的,Parquet是基于列的。但是,列被分成“行组”。这意味着可以只读取Parquet文件的一部分(即一个行组)。请参见https://parquet.apache.org/documentation/latest/和https://arrow.apache.org/docs/python/parquet.html#finer-grained-reading-and-writing 例如,Apache Spark能够在不同的机器上并行读取和处理相同Parquet文件的不同行组。 - mrteutone
然而,行组相当大。在Spark/Hadoop中,默认的组大小为128/256 MB。 - shay__
8
当你收到一个10GB大小、有十亿行数据的文件,而只需其中100万行就足够满足你的需要时,说它是正常的并没有什么帮助。 - Alonzorz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接