0Pricing
Pandas & NumPy Academy · Lekcja

Parquet: szybki magazyn kolumnowy

Zapisuj DataFrame Pandas w formacie Parquet za pomocą to_parquet(), odczytuj go szybciej niż CSV i używaj wyboru kolumn, aby wczytywać tylko potrzebne pola.

Parquet: szybki magazyn kolumnowy to bezpłatna lekcja Pandas & NumPy Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Pandas & NumPy Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Pandas & NumPy Academy zawiera 4 lekcji w sumie.

Czym jest Parquet?

Apache Parquet to kolumnowy binarny format plików przeznaczony do zastosowań analitycznych. W przeciwieństwie do formatu CSV, który przechowuje dane wierszami jako tekst, Parquet zapisuje każdą kolumnę w ciągłym bloku, skutecznie ją kompresuje i koduje metadane. Dzięki temu jest znacznie szybszy w przypadku zapytań odczytujących tylko kilka kolumn z szerokiej tabeli. Parquet to de facto standardowy format w jeziorach danych (AWS S3, Google Cloud Storage) i jest natywnie obsługiwany przez Pandas, Dask, Spark oraz BigQuery.

Zapisywanie danych Parquet za pomocą to_parquet()

Konwersja obiektu Pandas DataFrame do formatu Parquet wymaga wywołania jednej metody: df.to_parquet('output.parquet'). Domyślnym silnikiem jest pyarrow (instalowany za pomocą pip install pyarrow). Parquet dokładnie zachowuje typy danych kolumn — nie ma już problemu z odczytywaniem kolumn dat jako łańcuchów znaków. Obsługuje także kompresję od razu, za pomocą parametru compression; 'snappy' zapewnia szybki odczyt i zapis przy umiarkowanej kompresji, natomiast 'gzip' oferuje większą kompresję kosztem szybkości.

import pandas as pd
import numpy as np

# Create a sample DataFrame
np.random.seed(0)
df = pd.DataFrame({
    'date': pd.date_range('2024-01-01', periods=100000, freq='T'),
    'value': np.random.randn(100000),
    'category': np.random.choice(['A', 'B', 'C'], 100000)
})

# Write to Parquet
df.to_parquet('data.parquet', index=False, compression='snappy')
print('Written to data.parquet')

Odczytywanie danych Parquet za pomocą read_parquet()

pd.read_parquet('output.parquet') odczytuje plik z powrotem do obiektu DataFrame. W porównaniu z odczytem odpowiedniego pliku CSV odczytywanie Parquet jest zazwyczaj 5–10 razy szybsze w przypadku szerokich tabel z wieloma kolumnami. Typy danych są dokładnie zachowywane — daty pozostają typu datetime64, kategorie pozostają typu category, a liczby całkowite pozostają typu int32 lub int64, zgodnie z zapisem. Wnioskowanie typów nie jest potrzebne, ponieważ metadane są osadzone w pliku.

import pandas as pd
import time

# Read Parquet
start = time.time()
df = pd.read_parquet('data.parquet')
print(f'Read Parquet: {time.time()-start:.3f}s')
print(df.dtypes)
print(df.shape)

Przycinanie kolumn: odczytywanie tylko potrzebnych kolumn

Największą zaletą przechowywania kolumnowego jest przycinanie kolumn: można odczytywać tylko wybrane kolumny bez skanowania reszty pliku. Do parametru columns należy przekazać listę nazw kolumn. Jeśli tabela ma 100 kolumn, każda zajmuje 100 MB, a potrzebne są tylko 3 kolumny, Parquet odczyta 3 MB zamiast 10 GB. CSV musi przeskanować każdy znak, aby wyodrębnić dowolną kolumnę. Dzięki temu Parquet idealnie nadaje się do szerokich tabel w potokach analitycznych.

import pandas as pd

# Only load the 2 columns needed for this analysis
df = pd.read_parquet('large_table.parquet',
                     columns=['date', 'revenue'])
print(df.columns.tolist())
print(df.shape)
print(df.memory_usage(deep=True).sum() / 1e6, 'MB loaded')

Filtrowanie grup wierszy (predicate pushdown)

Parquet przechowuje statystyki (minimum/maksimum) dla każdej grupy wierszy (bloku wierszy) w stopce pliku. Po zastosowaniu filtra za pomocą parametru filters czytnik pomija całe grupy wierszy, w których filtr nie może znaleźć dopasowania — nazywa się to predicate pushdown. Na przykład filtrowanie dat w posortowanym chronologicznie pliku Parquet pomija całe bloki miesięcy znajdujące się poza zakresem i odczytuje tylko odpowiednie fragmenty. Silnik pyarrow obsługuje tę funkcję natywnie.

import pandas as pd

# Filter using predicate pushdown — row groups outside range are skipped
df = pd.read_parquet(
    'time_series.parquet',
    columns=['date', 'value'],
    filters=[('date', '>=', '2024-06-01'),
              ('date', '<', '2024-07-01')]
)
print(f'Loaded {len(df):,} rows (June only)')
print(df.head())

Parquet a CSV: porównanie

Oto praktyczne porównanie formatów Parquet i CSV dla zbioru danych zawierającego 10 milionów wierszy i 20 kolumn:

  • Rozmiar pliku: CSV ~2 GB, Parquet (snappy) ~400 MB
  • Czas odczytu (wszystkie kolumny): CSV ~15 s, Parquet ~2 s
  • Czas odczytu (3 kolumny): CSV ~15 s (musi przeskanować całość), Parquet ~0,3 s
  • Zachowanie typów danych: CSV traci typy danych, Parquet je zachowuje
  • Odczyt przez człowieka: CSV tak, Parquet nie (format binarny)

W produkcyjnych potokach, w których dane są zapisywane raz i odczytywane wielokrotnie, Parquet jest niemal zawsze lepszym wyborem.

Partycjonowane zbiory danych Parquet

W przypadku bardzo dużych zbiorów danych Parquet obsługuje partycjonowane zbiory danych: dane są dzielone na wiele plików uporządkowanych w hierarchii katalogów według wartości kolumn. Na przykład partycjonowanie według roku i miesiąca tworzy ścieżkę data/year=2024/month=01/part.parquet. Podczas odczytu partycjonowanego zbioru danych automatycznie filtrowane są katalogi odpowiadające zapytaniu. Jest to standardowy układ w jeziorach danych, który umożliwia wydajne zapytania zakresowe na miliardach wierszy.

import pandas as pd

# Write a partitioned dataset (requires pyarrow)
df = pd.read_parquet('all_data.parquet')
df['year'] = df['date'].dt.year
df['month'] = df['date'].dt.month

df.to_parquet(
    'partitioned_data/',
    partition_cols=['year', 'month'],
    index=False
)
# Creates: partitioned_data/year=2024/month=1/part-0.parquet etc.

Odczytywanie partycjonowanych zbiorów danych

Odczytywanie partycjonowanego katalogu Parquet jest identyczne z odczytywaniem pojedynczego pliku — Pandas (za pośrednictwem pyarrow) automatycznie wykrywa wszystkie pliki partycji. Wartości kolumny partycji są uwzględniane jako kolumny w wynikowym obiekcie DataFrame. Można także użyć filters, aby skorzystać z przycinania partycji, podczas którego całe poddrzewa katalogów są pomijane na podstawie wartości kolumny partycji. Dzięki temu odpytywanie partycjonowanego zbioru danych o rozmiarze 1 TB przypomina odczytywanie kilku MB.

import pandas as pd

# Read the entire partitioned dataset
df_all = pd.read_parquet('partitioned_data/')
print('All years:', df_all['year'].unique())

# Read only 2024 data using partition pruning
df_2024 = pd.read_parquet(
    'partitioned_data/',
    filters=[('year', '==', 2024)]
)
print('2024 rows:', len(df_2024))

Parquet z Dask

Dask natywnie odczytuje i zapisuje dane Parquet za pomocą dd.read_parquet() oraz ddf.to_parquet(). Każdy plik w partycjonowanym katalogu Parquet staje się jedną partycją Dask, co umożliwia w pełni równoległy odczyt. Dask korzysta także z predicate pushdown, gdy określono filtry. Zapisywanie dużego wyniku Dask do partycjonowanego zbioru danych Parquet to standardowy sposób tworzenia danych wyjściowych we współczesnych potokach inżynierii danych.

import dask.dataframe as dd

# Read partitioned Parquet with Dask (each file = one partition)
ddf = dd.read_parquet('partitioned_data/',
                      columns=['date', 'revenue', 'region'],
                      filters=[('year', '==', 2024)])

# Compute aggregation in parallel
result = ddf.groupby('region')['revenue'].sum().compute()
print(result.sort_values(ascending=False))

Opcje kompresji i kodowania

Parquet obsługuje wiele algorytmów kompresji i wewnętrznych schematów kodowania. Snappy (domyślny) stawia na szybkość przy umiarkowanym stopniu kompresji. Gzip pozwala uzyskać pliki mniejsze o około 30%, ale ich odczyt i zapis trwa dłużej. Zstd lepiej niż oba te algorytmy równoważy szybkość i stopień kompresji. W przypadku kolumn typu całkowitego Parquet automatycznie stosuje kodowanie różnicowe lub kodowanie słownikowe, aby dodatkowo zmniejszyć rozmiar, bez konieczności dodatkowej konfiguracji z Państwa strony.

import pandas as pd
import numpy as np

np.random.seed(0)
df = pd.DataFrame({'id': range(500000), 'val': np.random.randn(500000)})

for comp in ['snappy', 'gzip', 'zstd']:
    fname = f'data_{comp}.parquet'
    df.to_parquet(fname, compression=comp, index=False)
    import os
    size_mb = os.path.getsize(fname) / 1e6
    print(f'{comp}: {size_mb:.2f} MB')

Zastępowanie CSV w potoku

Najprostszym sposobem na wdrożenie Parquet jest dodanie jednorazowego etapu konwersji na początku projektu: jednokrotnie odczytać plik CSV, oczyścić dane i rzutować typy danych, a następnie zapisać dane jako Parquet. Wszystkie kolejne uruchomienia odczytują plik Parquet zamiast pliku CSV. Zapewnia to natychmiastowe korzyści w zakresie szybkości i zajętości miejsca przy minimalnych zmianach w kodzie. W przypadku nowych danych przychodzących w formacie CSV (np. nocnych eksportów) należy dodać do potoku etap konwersji, który zapisuje dane w formacie Parquet przed rozpoczęciem analizy.

import pandas as pd

# One-time conversion
df = pd.read_csv('raw_data.csv',
                 parse_dates=['date'],
                 dtype={'category': 'category',
                        'amount': 'float32'})
df.to_parquet('clean_data.parquet', index=False)

# All future reads use Parquet
df_fast = pd.read_parquet('clean_data.parquet')
print('Loaded from Parquet:', df_fast.dtypes.to_dict())

Szybkie sprawdzenie

Proszę sprawdzić swoją znajomość zagadnień analizy danych z tej lekcji.

Podsumowanie lekcji

W tej lekcji nauczyli się Państwo, że: to_parquet() i read_parquet() zapewniają szybszy, mniejszy i zachowujący typy danych zapis oraz odczyt plików w porównaniu z CSV, ograniczanie kolumn za pomocą parametru columns odczytuje tylko potrzebne kolumny, unikając skanowania całego pliku, a partycjonowane zbiory danych Parquet uporządkowane według wartości kolumn umożliwiają ograniczanie partycji, co usprawnia zapytania zakresowe w dużych jeziorach danych. W następnej części połączymy Pandas z relacyjnymi bazami danych za pomocą SQLAlchemy.

Często zadawane pytania

Czy lekcja „Parquet: szybki magazyn kolumnowy” jest bezpłatna?

Tak — pełny tekst „Parquet: szybki magazyn kolumnowy” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Pandas & NumPy Academy, przejdź na CoddyKit PRO. Kurs Pandas & NumPy Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Parquet: szybki magazyn kolumnowy”?

Zapisuj DataFrame Pandas w formacie Parquet za pomocą to_parquet(), odczytuj go szybciej niż CSV i używaj wyboru kolumn, aby wczytywać tylko potrzebne pola. Ćwiczysz Pandas & NumPy Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Pandas & NumPy Academy?

Nie wymagamy żadnego doświadczenia. Pandas & NumPy Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Parquet: szybki magazyn kolumnowy”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Pandas & NumPy Academy?

Tak. Każda lekcja Pandas & NumPy Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Strumieniowy odczyt CSV z chunksize
  2. Przyrostowa agregacja między porcjami
  3. Wprowadzenie do obiektów Dask DataFrame
  4. Parquet: szybki magazyn kolumnowy
← Powrót do Pandas & NumPy Academy