Pythonライブラリ「unstructured」徹底解説:非構造化データ処理の決定版 🧱

Python

現代社会では、テキスト文書、PDF、HTML、画像など、形式が定まっていない「非構造化データ」が爆発的に増加しています。IDCの予測によれば、2025年までに全データの80%が非構造化データになるとも言われています。これらのデータには価値ある情報が眠っていますが、その形式の多様さから分析や活用が難しいという課題があります。

この課題に取り組むために開発されたのが、Pythonライブラリ「unstructured」です。unstructuredは、様々な形式の非構造化データを簡単に、そして効率的に処理するための強力なツールキットを提供します。特に、大規模言語モデル(LLM)を用いたアプリケーション、例えばRAG(Retrieval-Augmented Generation)システムの開発において、データの前処理工程を大幅に簡略化できるため、注目を集めています。

このブログ記事では、unstructuredライブラリの基本的な使い方から、主要な機能、応用例までを詳しく解説していきます。この記事を読めば、あなたもunstructuredを使いこなし、非構造化データ活用の第一歩を踏み出せるはずです!🚀

1. unstructuredとは?🤔

unstructuredは、PDF、HTML、Word文書(.docx)、PowerPointプレゼンテーション(.pptx)、画像(.png, .jpg)、メール(.eml)など、多種多様なファイル形式からテキストやメタデータを抽出し、構造化された形式に変換(パーティショニング)するためのオープンソースPythonライブラリです。

主な目的は、特にLLMのような機械学習モデルが扱いやすいように、非構造化データを前処理することです。これにより、開発者はデータの前処理にかかる時間と労力を削減し、より高度な分析やアプリケーション開発に集中できます。

unstructuredは活発に開発されており、機能改善や対応ファイル形式の追加が継続的に行われています。

2. インストール 💻

unstructuredのインストールはpipを使って簡単に行えます。Python 3.9以上が必要です。

基本インストール

基本的なテキストファイル(.txt)、HTML、XML、JSON、Email形式のみを扱う場合は、以下のコマンドでインストールできます。これには追加の依存関係はほとんどありません。

pip install unstructured
特定ファイル形式のサポート追加

PDFやWord文書など、特定のファイル形式を処理するには、追加の依存関係が必要です。角括弧 `[]` を使って必要な形式を指定します。

例:Word文書 (.docx) のサポートを追加する場合

pip install "unstructured[docx]"

例:PDFファイルのサポートを追加する場合

pip install "unstructured[pdf]"

例:画像のサポートを追加する場合(OCR機能を含む)

pip install "unstructured[image]"

注意: PDFや画像の処理には、`tesseract-ocr` や `poppler-utils` といったシステムレベルの依存関係のインストールが別途必要になる場合があります。お使いのOSに合わせてインストールしてください(例:macOSなら `brew install tesseract poppler`)。

全ファイル形式のサポート

サポートされている全てのファイル形式の依存関係を一度にインストールするには、以下のコマンドを実行します。

pip install "unstructured[all-docs]"

注意: これにより多くのライブラリがインストールされるため、環境によっては時間がかかったり、サイズが大きくなる可能性があります。また、前述のシステムレベルの依存関係(`libmagic`, `tesseract`, `poppler`, `libreoffice`, `pandoc` など)も必要に応じてインストールする必要があります。

Windows環境でのインストールや、より詳細な依存関係については、公式のインストールガイドを参照してください。(リンク先のURLは検索結果に基づいています)

また、ローカルでの高度な推論(特にPDFや画像のレイアウト解析)を行いたい場合は、`local-inference` オプションをつけてインストールすることが推奨される場合があります。これにより、`detectron2`などのモデル関連のライブラリがインストールされます。

pip install "unstructured[local-inference]"

2023年頃には、このインストールに時間がかかるという報告もありました。

3. 基本的な使い方:パーティショニング 🧩

unstructuredの最も基本的な機能は「パーティショニング(Partitioning)」です。これは、入力されたドキュメントを意味のある要素(タイトル、本文テキスト、リスト項目、テーブルなど)に分割し、それぞれのテキスト内容とメタデータ(ファイル名、ページ番号、要素タイプなど)を抽出するプロセスです。

最も簡単な方法は、`partition`関数を使うことです。この関数はファイルタイプを自動検出し、適切な内部関数に処理を振り分けます。

例:テキストファイルのパーティショニング

from unstructured.partition.auto import partition

# ファイルパスを指定してパーティショニング
elements = partition(filename="example.txt")

for element in elements:
    print(f"Type: {type(element)}, Text: {element.text[:100]}...") # テキストが長い場合に備えて最初の100文字だけ表示
    print(f"Metadata: {element.metadata.to_dict()}")
    print("-" * 20)

# ファイルオブジェクトを渡すことも可能 (libmagicが必要な場合あり)
# with open("example.txt", "rb") as f:
#     elements = partition(file=f)

`partition`関数は、`Element`オブジェクトのリストを返します。各`Element`は、ドキュメント内の特定のセクション(例えば、タイトルや段落)を表します。

`libmagic` ライブラリがインストールされていると、ファイルの内容に基づいてより正確にファイルタイプを検出できます。インストールされていない場合は、ファイル拡張子に基づいて検出が試みられます。

例:HTMLファイルのパーティショニング

from unstructured.partition.html import partition_html

# HTMLファイルのパスを指定
elements = partition_html(filename="example.html")

# URLを指定することも可能 (requestsライブラリが必要な場合あり pip install "unstructured")
# elements = partition_html(url="https://example.com")

for element in elements:
    print(f"Type: {type(element)}, Category: {element.category}, Text: {element.text[:100]}...")
    print(f"Metadata: {element.metadata.to_dict()}")
    print("-" * 20)

特定のファイルタイプに対応する関数(例:`partition_html`, `partition_pdf`)も用意されています。これらを使うと、より詳細なオプションを指定できます。

例:PDFファイルのパーティショニング

PDFの処理には依存関係のインストールが必要です (`pip install "unstructured[pdf]"`)。また、システムに`poppler-utils`や`tesseract-ocr`が必要な場合があります。

from unstructured.partition.pdf import partition_pdf

elements = partition_pdf(
    filename="example.pdf",
    strategy="hi_res",  # 高解像度戦略を使用(後述)
    infer_table_structure=True, # テーブル構造の推論を有効化
    extract_images_in_pdf=False # PDF内の画像の抽出は無効化(必要ならTrueに)
)

for element in elements:
    # テーブル要素は特別な処理が可能
    if isinstance(element, unstructured.documents.elements.Table):
        print(f"--- Found Table ---")
        # print(element.metadata.text_as_html) # HTML形式でテーブルを出力
        print(element.text[:200]) # テーブルのテキスト表現
        print(f"Metadata: {element.metadata.to_dict()}")
    else:
        print(f"Type: {type(element)}, Category: {element.category}, Text: {element.text[:100]}...")
        print(f"Metadata: {element.metadata.to_dict()}")
    print("-" * 20)

PDFのパーティショニングでは、`strategy`パラメータで処理戦略を選択できます(詳細は後述)。テーブル構造の推論や画像抽出などもオプションで制御可能です。

4. 主要な機能と概念 ✨

要素 (Elements)

パーティショニングによってドキュメントは複数の「要素 (Element)」に分割されます。unstructuredは様々な要素タイプを定義しており、それぞれがドキュメント内の特定の意味的単位を表します。主な要素タイプには以下のようなものがあります。

  • Title: 文書やセクションのタイトル
  • NarrativeText: 主要な本文テキスト、段落
  • ListItem: リストの項目
  • Table: 表形式のデータ
  • Image: 画像 (テキストがOCRで抽出される場合あり)
  • Header / Footer: ヘッダーやフッター
  • Address: 住所情報
  • EmailAddress: メールアドレス
  • URL: ウェブサイトのURL

各要素はテキスト内容 (`element.text`) に加えて、豊富なメタデータ (`element.metadata`) を保持しています。メタデータには、ファイル名、ページ番号、要素のカテゴリ(`element.category`と同等)、要素ID、検出された言語などが含まれることがあります。これらの情報は、後のデータ処理や検索において非常に役立ちます。

チャンキング (Chunking) 🧱

LLMは一度に扱えるテキストの長さ(コンテキストウィンドウ)に制限があるため、長いドキュメントを処理する際には、適切なサイズの「チャンク」に分割する必要があります。unstructuredは、パーティショニングで得られた要素を基にした高度なチャンキング機能を提供します。

従来のチャンキング手法は、改行文字 (`\n\n`) などに基づいて単純にテキストを分割することが多いですが、unstructuredのチャンキングは、ドキュメントの構造(要素タイプ)を考慮します。パーティショニングによって得られた意味的な単位(要素)をできるだけ維持しつつ、指定された最大チャンクサイズを超えないように要素を組み合わせたり、大きすぎる要素を分割したりします。

チャンキングは、パーティショニングの後処理として実行されますが、`partition_*` 関数の引数で同時に指定することも可能です。

from unstructured.chunking.title import chunk_by_title
from unstructured.partition.auto import partition

# まずパーティショニングを実行
elements = partition(filename="long_document.md")

# タイトルに基づいてチャンキングを実行
chunks = chunk_by_title(
    elements,
    max_characters=1000, # チャンクの最大文字数 (ソフトリミット)
    new_after_n_chars=800, # この文字数を超えたら新しいチャンクを開始する目安
    combine_text_under_n_chars=500 # この文字数未満の小さな要素は前のチャンクと結合する
)

for i, chunk in enumerate(chunks):
    print(f"--- Chunk {i+1} ---")
    print(chunk.text[:200]) # チャンクのテキスト内容
    # チャンクを構成する元の要素の情報もメタデータに含まれる
    # print(chunk.metadata.to_dict())
    print("-" * 20)

# パーティショニングと同時にチャンキングを指定する例 (PDF)
# chunks = partition_pdf(
#     filename="report.pdf",
#     chunking_strategy="by_title", # チャンキング戦略を指定
#     max_characters=1000,
#     combine_text_under_n_chars=500,
#     # 他のpartition_pdfの引数...
# )

利用可能なチャンキング戦略 (`chunking_strategy`) には以下のようなものがあります。

  • "basic": 要素を順番に結合していき、`max_characters` を超えないようにチャンクを作成します。
  • "by_title": `Title`要素をチャンクの開始点として、セクションごとにチャンクを作成しようとします。レポートや論文など、構造が明確なドキュメントに適しています。
  • "by_page" (API経由などで利用可能): ページ番号に基づいてチャンクを作成します。

チャンキングによって生成されるのは、`CompositeElement`(複数の要素を組み合わせたもの)、`Table`、または `TableChunk`(大きすぎるテーブルを分割したもの)のいずれかのタイプのオブジェクトです。

クリーニング (Cleaning)

抽出されたテキストには、不要な定型文(ヘッダー、フッター、広告など)や、特殊文字、余分な空白が含まれていることがあります。unstructuredは、これらのノイズを除去するためのクリーニング関数も提供しています。

例えば、抽出された要素リストに対して、特定のパターンのテキストを削除したり、短い要素を除去したりすることができます。

from unstructured.cleaners.core import clean, clean_extra_whitespace, remove_punctuation
from unstructured.partition.auto import partition

elements = partition(filename="messy_document.html")

cleaned_elements = []
for element in elements:
    # 例: 特定の不要なテキストを削除し、余分な空白を除去し、句読点を削除
    element.text = clean(element.text, bullets=True, extra_whitespace=True) # 箇条書き記号や余分な空白を除去
    # element.text = remove_punctuation(element.text) # 句読点を削除 (必要に応じて)

    # 例: 短すぎる要素を除外
    if len(element.text.strip()) > 20:
         cleaned_elements.append(element)

print(f"Original elements: {len(elements)}, Cleaned elements: {len(cleaned_elements)}")

クリーニング機能は、LLMへの入力品質を高める上で重要です。

5. サポートされているファイル形式 📄

unstructuredは非常に多くのファイル形式に対応しています。以下はその一部です(完全なリストや最新情報は公式ドキュメントをご確認ください)。

カテゴリファイル拡張子備考
テキスト.txt基本サポート
Web.html, .htm, .xml基本サポート
ドキュメント.pdf依存関係 `[pdf]` 必要。システム依存 (`poppler`, `tesseract`) も必要になる場合あり。
.docx, .doc依存関係 `[docx]` 必要。システム依存 (`libreoffice`) が必要になる場合あり。
.pptx, .ppt依存関係 `[pptx]` 必要。システム依存 (`libreoffice`) が必要になる場合あり。
.odt依存関係 `[odt]` 必要。システム依存 (`libreoffice`) が必要になる場合あり。
.md依存関係 `[md]` 必要。
.epub依存関係 `[epub]` 必要。システム依存 (`pandoc`) が必要になる場合あり。
.rtf依存関係 `[rtf]` 必要。システム依存 (`pandoc` v2.14.2+) が必要になる場合あり。
表計算.xlsx, .xls依存関係 `[xlsx]` 必要。
.csv, .tsv依存関係 `[csv]`, `[tsv]` 必要。
画像.png, .jpg, .jpeg, .tiff, .bmp, .heic依存関係 `[image]` 必要。OCRのためにシステム依存 (`tesseract`) が必要。
メール.eml, .msg基本サポート(.msgは依存関係 `[msg]` 必要)。
データ形式.json基本サポート。

多くの形式で、`pip install "unstructured[ファイル形式]"` のように追加の依存関係をインストールする必要があります。また、特にPDF、Office文書、画像などの処理には、`tesseract-ocr`, `poppler-utils`, `libreoffice`, `pandoc`, `libmagic-dev` といったシステムライブラリが必要になることがあります。Dockerを使用すると、これらのシステム依存関係の管理が容易になる場合があります。

6. ユースケースと応用例 🚀

unstructuredライブラリは、その強力なデータ処理能力から、様々な分野で活用されています。

  • RAG (Retrieval-Augmented Generation) システムの構築: 社内ドキュメントやウェブサイトなど、様々なソースからの情報をLLMが参照できるようにするために、ドキュメントを解析し、検索可能なチャンクに分割する前処理パイプラインの中核として利用されます。抽出されたメタデータ(出典ファイル名、ページ番号など)も検索精度や回答の信頼性向上に役立ちます。
  • データ分析・抽出: レポート、契約書、メールなどから特定の情報(数値、日付、人名、組織名など)を抽出・構造化し、分析可能な形式に変換します。テーブルデータの抽出機能も強力です。
  • ドキュメント変換・正規化: 多様な形式のドキュメントを統一されたJSON形式やプレーンテキストに変換し、後続のシステム(データベース、検索エンジンなど)への投入を容易にします。
  • コンテンツ管理システムの強化: アップロードされたドキュメントの内容を自動的に解析・分類し、タグ付けや要約生成を行うことで、コンテンツの検索性や管理効率を向上させます。
  • 学術研究: 大量の論文PDFからテキストや参考文献、図表情報を抽出し、文献レビューやメタ分析を支援します。

LangChainのようなLLMアプリケーション開発フレームワークとも連携しやすく、`UnstructuredLoader` や `UnstructuredFileLoader` といった形で簡単に組み込むことができます。

Unstructured API: 開発元は、本番環境での利用や、常に最新のモデル・機能を利用したい場合には、オープンソースライブラリではなく、Unstructured API(有償の場合あり)の利用を推奨しています。APIを利用することで、ローカルでの複雑な依存関係管理やコンピュータリソースの心配なく、高品質な処理結果を得ることができます。無料枠も提供されている場合があります。

7. まとめ ✨

Pythonライブラリ「unstructured」は、現代のデータ環境における非構造化データ処理の課題に対する強力なソリューションです。

  • 多様なファイル形式(PDF, HTML, DOCX, 画像など)に対応。
  • ドキュメントを意味のある要素に分割する「パーティショニング」機能。
  • LLMに適したサイズに分割する高度な「チャンキング」機能。
  • 不要なテキストを除去する「クリーニング」機能。
  • 処理速度と精度を調整できる「戦略」オプション。
  • RAGシステム構築やデータ分析など、幅広い応用が可能。

インストールや依存関係の管理には少し注意が必要な場合もありますが、それを乗り越えれば、非構造化データから価値ある情報を引き出すための強力な武器となります。

ぜひ、unstructuredライブラリをあなたのプロジェクトに導入し、非構造化データ活用の可能性を広げてみてください!💪

コメント

タイトルとURLをコピーしました