# Pandas

[Pandas](https://github.com/pandas-dev/pandas)는 널리 사용되는 Python 데이터 분석 툴킷입니다. 원격 데이터를 읽고 쓰는 데 [fsspec](https://filesystem-spec.readthedocs.io)을 사용하므로, Hugging Face 경로([`hf://`](/docs/huggingface_hub/guides/hf_file_system#integrations))를 사용하여 Hub에서 데이터를 읽고 쓸 수 있습니다.

## DataFrame 로드

로컬 파일 또는 Hugging Face Datasets와 같은 원격 저장소에서 데이터를 로드할 수 있습니다. Pandas는 CSV, JSON, Parquet 등 다양한 포맷을 지원합니다:

```python
>>> import pandas as pd
>>> df = pd.read_csv("path/to/data.csv")
```

Hugging Face에서 파일을 로드하려면 경로가 `hf://`로 시작해야 합니다. 예를 들어, [stanfordnlp/imdb](https://huggingface.co/datasets/stanfordnlp/imdb) 데이터셋 저장소의 경로는 `hf://datasets/stanfordnlp/imdb`입니다. Hugging Face의 데이터셋에는 여러 Parquet 파일이 포함되어 있습니다. Parquet 파일 형식은 데이터프레임의 읽기 및 쓰기를 효율적으로 만들고, 데이터 분석 언어 간 데이터 공유를 쉽게 하도록 설계되었습니다. `plain_text/train-00000-of-00001.parquet` 파일을 로드하는 방법은 다음과 같습니다:

```python
>>> import pandas as pd
>>> df = pd.read_parquet("hf://datasets/stanfordnlp/imdb/plain_text/train-00000-of-00001.parquet")
>>> df
                                                    text  label
0      I rented I AM CURIOUS-YELLOW from my video sto...      0
1      "I Am Curious: Yellow" is a risible and preten...      0
2      If only to avoid making this type of film in t...      0
3      This film was probably inspired by Godard's Ma...      0
4      Oh, brother...after hearing about this ridicul...      0
...                                                  ...    ...
24995  A hit at the time but now better categorised a...      1
24996  I love this movie like no other. Another time ...      1
24997  This film and it's sequel Barry Mckenzie holds...      1
24998  'The Adventures Of Barry McKenzie' started lif...      1
24999  The story centers around Barry McKenzie who mu...      1
```

Hugging Face 경로 및 구현 방식에 대한 자세한 내용은 [HfFileSystem에 대한 클라이언트 라이브러리 문서](/docs/huggingface_hub/guides/hf_file_system)를 참고하세요.

> [!TIP]
> 동일한 `hf://` 경로도 [Storage Buckets](./storage-buckets)에서 사용할 수 있습니다:
> ```python
> >>> df = pd.read_parquet("hf://buckets/username/my-bucket/data.parquet")
> >>> df.to_parquet("hf://buckets/username/my-bucket/output.parquet")
> ```

## DataFrame 저장

`to_csv/to_json/to_parquet`를 사용하여 pandas DataFrame을 로컬 파일 또는 Hugging Face에 직접 저장할 수 있습니다.

Hugging Face에 DataFrames를 저장하려면 먼저 [Hugging Face 계정으로 로그인](/docs/huggingface_hub/quick-start#login)해야 합니다. 예를 들어 다음을 사용할 수 있습니다:

```
hf auth login
```

그 후 [데이터셋 저장소를 생성](/docs/huggingface_hub/quick-start#create-a-repository)할 수 있습니다. 예를 들어 다음을 사용할 수 있습니다:

```python
from huggingface_hub import HfApi

HfApi().create_repo(repo_id="username/my_dataset", repo_type="dataset")
```

마지막으로, Pandas에서 [Hugging Face 경로](/docs/huggingface_hub/guides/hf_file_system#integrations)를 사용할 수 있습니다:

```python
import pandas as pd

df.to_parquet("hf://datasets/username/my_dataset/imdb.parquet")

# or write in separate files if the dataset has train/validation/test splits
df_train.to_parquet("hf://datasets/username/my_dataset/train.parquet")
df_valid.to_parquet("hf://datasets/username/my_dataset/validation.parquet")
df_test .to_parquet("hf://datasets/username/my_dataset/test.parquet")
```

Hugging Face의 Parquet 파일은 저장 효율성을 높이고, 다운로드 및 업로드를 가속화하며, 효율적인 데이터셋 스트리밍 및 편집을 가능하도록 최적화되어 있습니다:

* [Parquet Content Defined Chunking](https://huggingface.co/blog/parquet-cdc)은 Hugging Face의 스토리지 백엔드인 [Xet](https://huggingface.co/docs/hub/en/xet/index)에 최적화된 Parquet입니다. 청크 기반 중복 제거를 통해 업로드와 다운로드를 가속화하며, 효율적인 파일 편집을 가능하게 합니다.
* Page index는 스트리밍 시 필터를 가속화하고, [Dataset Viewer](https://huggingface.co/docs/dataset-viewer)와 같은 환경에서 효율적인 랜덤 액세스를 가능하게 합니다.

Pandas는 최적화된 Parquet 파일을 작성하려면 추가 인수가 필요합니다:

```python
import pandas as pd

df.to_parquet(
    "hf://datasets/username/my_dataset/imdb.parquet",
    # Optimize for Xet
    use_content_defined_chunking=True,
    write_page_index=True,
)
```

* `use_content_defined_chunking=True`를 설정하여 Parquet Content Defined Chunking을 활성화합니다. [중복 제거](https://huggingface.co/blog/parquet-cdc) 및 [편집](./datasets-editing)에 사용됩니다(`pyarrow>=21.0` 필요).
* `write_page_index=True`를 설정하여 Parquet 메타데이터에 페이지 인덱스를 포함하면 [스트리밍 및 랜덤 액세스](./datasets-streaming)가 가능합니다.

> [!TIP]
> Content defined chunking(CDC)은 Parquet writer가 중복 데이터가 동일하게 chunking되고 압축되도록 데이터 페이지를 chunking합니다. CDC가 없으면 페이지는 임의로 chunking되므로, 압축으로 인해 중복 데이터를 감지하는 것이 불가능합니다. CDC 덕분에 중복 데이터는 한 번만 업로드 또는 다운로드되므로, Hugging Face로의 Parquet 업로드 및 다운로드가 더 빨라집니다.

Xet에 대한 자세한 내용은 [여기](https://huggingface.co/join/xet)에서 확인하세요.

## Parquet에 Xet 중복 제거 활용

최적화된 Parquet 파일은 중복 제거를 가능하게 하는 Content Defined Chunking으로 작성됩니다. 이는 Hugging Face에 이미 존재하는 데이터 청크를 다시 업로드할 필요가 없으므로 업로드 속도를 높이고, 상당한 I/O를 절약합니다.

예를 들어, 이 코드는 `df`의 내용을 업로드한 후 `edited_df`의 경우 변경된 청크만 업로드하므로 업로드 속도가 더 빠릅니다:

```python
import pandas as pd

df.to_parquet(
    "hf://datasets/username/my_dataset/imdb.parquet",
    # Optimize for Xet
    use_content_defined_chunking=True,
    write_page_index=True,
)

edited_df = ...  # e.g. with added/modified/removed rows or columns

edited_df.to_parquet(
    "hf://datasets/username/my_dataset/imdb.parquet",
    # Optimize for Xet
    use_content_defined_chunking=True,
    write_page_index=True,
)
```

Chunk은 약 64kB이며 Parquet는 컬럼별로 데이터를 저장하므로, 실제로 Optimized Parquet 파일을 편집할 때 다음과 같은 일이 발생합니다:

* 새로운 열을 추가하면 -> 새로운 열의 청크만 업로드됩니다
* add/edit/delete a row -> 컬럼당 하나의 chunk가 업로드됩니다

그리고 이 외에도 메타데이터를 포함하는 Parquet 푸터의 청크도 업로드됩니다.

## 이미지 사용

이미지 이름 또는 경로 필드를 포함하는 메타데이터 파일이 있는 폴더를 다음과 같은 구조로 로드할 수 있습니다:

```
Example 1:            Example 2:
folder/               folder/
├── metadata.csv      ├── metadata.csv
├── img000.png        └── images
├── img001.png            ├── img000.png
...                       ...
└── imgNNN.png            └── imgNNN.png
```

이미지 경로를 다음과 같이 반복할 수 있습니다:

```python
import pandas as pd

folder_path = "path/to/folder/"
df = pd.read_csv(folder_path + "metadata.csv")
for image_path in (folder_path + df["file_name"]):
    ...
```

데이터셋이 [지원되는 구조](https://huggingface.co/docs/hub/en/datasets-image#additional-columns)(`file_name` 필드가 포함된 `metadata.csv` 또는 `.jsonl` 파일)를 가지고 있으므로, 이 데이터셋을 Hugging Face에 저장하면 Dataset Viewer에서 Hugging Face에 메타데이터와 이미지가 모두 표시됩니다.

```python
from huggingface_hub import HfApi
api = HfApi()

api.upload_folder(
    folder_path=folder_path,
    repo_id="username/my_image_dataset",
    repo_type="dataset",
)
```

### 이미지 메서드와 Parquet

[pandas-image-methods](https://github.com/lhoestq/pandas-image-methods)를 사용하면 이미지 열에 `PIL.Image` 메서드를 사용할 수 있습니다. 또한 이미지와 메타데이터를 모두 포함하는 단일 Parquet 파일로 데이터셋을 저장하는 기능도 제공합니다:

```python
import pandas as pd
from pandas_image_methods import PILMethods

pd.api.extensions.register_series_accessor("pil")(PILMethods)

df["image"] = (folder_path + df["file_name"]).pil.open()
df.to_parquet("data.parquet")
```

모든 `PIL.Image` 메서드를 사용할 수 있습니다. 예를 들어

```python
df["image"] = df["image"].pil.rotate(90)
```

## Audios 사용

메타데이터 파일에 오디오의 이름 또는 경로에 대한 필드가 포함된 폴더를 다음과 같은 구조로 로드할 수 있습니다:

```
Example 1:            Example 2:
folder/               folder/
├── metadata.csv      ├── metadata.csv
├── rec000.wav        └── audios
├── rec001.wav            ├── rec000.wav
...                       ...
└── recNNN.wav            └── recNNN.wav
```

음성 파일 경로를 다음과 같이 반복할 수 있습니다:

```python
import pandas as pd

folder_path = "path/to/folder/"
df = pd.read_csv(folder_path + "metadata.csv")
for audio_path in (folder_path + df["file_name"]):
    ...
```

데이터셋이 [지원되는 구조](https://huggingface.co/docs/hub/en/datasets-audio#additional-columns)(`file_name` 필드가 포함된 `metadata.csv` 또는 `.jsonl` 파일)를 가지고 있으므로 Hugging Face에 저장할 수 있으며, Hub Dataset Viewer에서는 메타데이터와 오디오를 모두 확인할 수 있습니다.

```python
from huggingface_hub import HfApi
api = HfApi()

api.upload_folder(
    folder_path=folder_path,
    repo_id="username/my_audio_dataset",
    repo_type="dataset",
)
```

### 오디오 메서드와 Parquet

[pandas-audio-methods](https://github.com/lhoestq/pandas-audio-methods)를 사용하면 오디오 컬럼에 `soundfile` 메서드를 사용할 수 있습니다. 또한 오디오와 메타데이터를 모두 포함하는 단일 Parquet 파일로 데이터셋을 저장하는 기능도 제공합니다:

```python
import pandas as pd
from pandas_audio_methods import SFMethods

pd.api.extensions.register_series_accessor("sf")(SFMethods)

df["audio"] = (folder_path + df["file_name"]).sf.open()
df.to_parquet("data.parquet")
```

`librosa`와 함께 사용하기 쉬워집니다. 예를 들어 리샘플링에 사용할 수 있습니다:

```python
df["audio"] = [librosa.load(audio, sr=16_000) for audio in df["audio"]]
df["audio"] = df["audio"].sf.write()
```

## Transformers 사용

`transformers` 파이프라인을 pandas DataFrame에 적용하여 분류, 텍스트 생성, 이미지 생성 등의 작업을 수행할 수 있습니다. 이 섹션에서는 진행 표시줄을 위해 `tqdm`를 사용한 몇 가지 예제를 보여줍니다.

> [!TIP]
> Pipelines는 `tqdm` 객체를 입력으로 받지 않지만, `x for x in tqdm(...)` 형태의 Python 생성기를 대신 사용할 수 있습니다.

### 텍스트 분류

```python
from transformers import pipeline
from tqdm import tqdm

pipe = pipeline("text-classification", model="clapAI/modernBERT-base-multilingual-sentiment")

# Compute labels
df["label"] = [y["label"] for y in pipe(x for x in tqdm(df["text"]))]
# Compute labels and scores
df[["label", "score"]] = [(y["label"], y["score"]) for y in pipe(x for x in tqdm(df["text"]))]
```

### 텍스트 생성

```python
from transformers import pipeline
from tqdm import tqdm

pipe = pipeline("text-generation", model="Qwen/Qwen2.5-1.5B-Instruct")

# Generate chat response
prompt = "What is the main topic of this sentence ? REPLY IN LESS THAN 3 WORDS. Sentence: '{}'"
df["output"] = [y["generated_text"][1]["content"] for y in pipe([{"role": "user", "content": prompt.format(x)}] for x in tqdm(df["text"]))]
```

