著者:Sorsa Editorial

2026年6月13日公開。2026年7月3日更新:料金を1,000ツイートあたりの単価に見直し、100回の無料リクエストによるスタートを追加、X API のコスト比較を刷新しました。公式 X API の従量課金レートは2026年7月に確認済みです。

要点: 機械学習用のTwitter(X)データセットを構築するとは、API からツイートを収集し、クリーニングと重複排除を行い、タスク向けにラベル付けし、学習用・検証用・テスト用のセットに分割して、JSONL のような形式にエクスポートすることを指します。無料 API とオープンなスクレイパーが使えなくなって以降、新規の収集は有料のデータ API を経由するようになりました。

その最後の点が実務上のハードルです。無料 API プランは2023年以降なくなり、snscrape や twint のようなスクレイパーも動かなくなったため、新鮮でテーマに沿ったコーパスはデータ API から得るしかありません。読み取り専用の Twitter/X 代替である Sorsa API は、公開ツイートとプロフィールを単一のヘッダーでプレーンな JSON として返し、収集向けに作られた検索・タイムライン・一括取得のエンドポイントを備えています。課金はフラットで、1回の呼び出しは返る量にかかわらず1リクエストとして数えられ、作者プロフィールは無料で付いてきて、1回の一括呼び出しで最大100件のツイート ID をリハイドレート(本文を再取得)できます。研究者が公開する ID のみのデータセットが復元されるのは、この仕組みによるものです。バッチエンドポイントでは、Sorsa は Proプランで1,000ツイートあたり約$0.02(Starter では$0.049から)となり、クレジットカード不要・有効期限なしの100回分の無料リクエストが40個のエンドポイント全体をカバーするため、課金が始まる前にパイプラインを試せます。

目次

機械学習用のTwitterデータセットはどう構築する? {#how-do-you-build-a-twitter-dataset-for-machine-learning}

Twitterデータセットの構築は5つの段階を通ります。API から生のツイートを収集し、クリーニングと重複排除を行い、タスク向けにラベル付けし、学習用・検証用・テスト用のセットに分割し、JSONL のような学習用フォーマットにエクスポートします。同じパイプラインが、分類データセットにも、言語モデル向けの命令チューニング用セットにも使えます。変わるのはラベル付けの段階だけです。

データではなく目的から始めましょう。感情分類器には、ポジティブ・ネガティブ・ニュートラルのラベルが明確な短いツイートが必要です。命令チューニングされたモデルには、プロンプトと応答のペアが必要です。ドメイン適応の実行には、軽いラベルまたはラベルなしの、テーマに沿った大量のテキストプールが必要です。目標を知ることで、ツイートを1件も取得する前に、クエリ・量・スキーマが決まります。

作業はきれいに分かれます。収集とリハイドレートは API の問題で、以下でコードとともに扱います。ラベル付け・正規化・分割は、Python でローカルに処理するデータの問題です。本ガイドの残りではそれぞれを順に取り上げ、多くの古いチュートリアルを破綻させる2026年の制約を、影響が出る箇所で指摘します。

自作すべきか、公開データセットを使うべきか? {#should-you-build-your-own-dataset-or-use-a-public-one}

タスクに合致する公開データセットが既にあるならそれを使い、テーマ・言語・期間・ラベルが自分に固有であれば自作しましょう。Hugging Face や Kaggle の公開セットは無料ですぐに読み込めますが、範囲が固定されており、多くは数年前のもので、英語のみのことも多く、その多くはツイート ID として配布されるため、本文が存在する前にリハイドレートする必要があります。

まず、よく知られた選択肢を押さえておく価値があります。Sentiment140 は感情のラベルが付いた約160万件のツイートを収録しており、Cardiff NLP の TweetEval ベンチマーク は7つのツイート分類タスク(皮肉、ヘイト、攻撃的表現、スタンス、絵文字、感情、センチメント)をまとめています。汎用的な英語の感情・情動モデルであれば、これらのいずれかを読み込むほうが、自分で収集するより効率的です。

ギャップが本物のときは自作しましょう。

  • テーマが狭い、または最近のもので、それをカバーする公開セットがない。
  • 公開セットが飛ばしている言語や地域が必要。
  • 2017年のツイートではなく、新しい期間が必要。
  • 自分のラベル体系が、既存のどのデータセットとも一致しない。

特に感情分析のケースについては、データが揃った後のモデリング側を Python でツイートの感情分析を行う ガイドで解説しています。

2026年にデータセット用のツイートを収集する方法 {#how-to-collect-tweets-for-a-dataset-in-2026}

ツイートは3つの経路で収集します。テーマ別コーパスにはキーワードと検索コマンドによる検索、アカウント別コーパスにはユーザータイムライン、キュレーションされたソースにはリストまたはコミュニティです。無料 API プランは2023年に終了し、snscrape や twint のようなスクレイパーも動かなくなったため、規模の大小を問わず、新規の収集は今や、検索とタイムラインの結果を直接返すデータ API を経由します。

読み取り専用 API なら、この作業は短いループにまとめられます。エンドポイントにクエリを送り、1ページ分のツイートを読み、カーソルをたどって、各ツイートをファイルに書き込む、という流れです。Sorsa の検索エンドポイントは、lang:since:until:-filter:retweets のような標準的な Twitter の高度な検索コマンド を受け付け、作者プロフィールを添えて1ページあたり約20件のツイートを返し、next_cursor で次のページを取得できます。構文に不慣れな場合は、まず ビジュアルな検索クエリビルダー でクエリを組み立てましょう。

python
import json, time, requests

API_KEY = "YOUR_SORSA_API_KEY"
BASE = "https://api.sorsa.io/v3"
HEADERS = {"ApiKey": API_KEY, "Content-Type": "application/json"}

def collect(query, target=5000):
    rows, cursor = [], None
    while len(rows) < target:
        body = {"query": query, "order": "latest"}
        if cursor:
            body["next_cursor"] = cursor
        r = requests.post(f"{BASE}/search-tweets", headers=HEADERS, json=body, timeout=30)
        if r.status_code == 429:
            time.sleep(1)
            continue
        r.raise_for_status()
        data = r.json()
        for t in data.get("tweets", []):
            rows.append({
                "id": str(t["id"]),
                "text": t.get("full_text", ""),
                "lang": t.get("lang", ""),
                "created_at": t.get("created_at", ""),
                "username": (t.get("user") or {}).get("username", ""),
            })
        cursor = data.get("next_cursor")
        if not cursor:
            break
    return rows

with open("tweets.jsonl", "w", encoding="utf-8") as f:
    for row in collect('"your topic" lang:en -filter:retweets', target=5000):
        f.write(json.dumps(row, ensure_ascii=False) + "\n")

アカウント別コーパスでは、検索呼び出しをユーザー名付きのユーザータイムラインエンドポイントに差し替えます。キュレーションされたソースには、キュレーションされたリストやコミュニティのフィードから取得 します。バランスを取ってサンプリングするために、メンションエンドポイントには min_likessince_dateuntil_date などのフィルターがあり、たとえば特定の期間内でエンゲージメントの高いツイートだけを取得できます。

効率について2点。作者プロフィールがすべてのツイートに同梱されているため、ハンドル・フォロワー数・アカウントの登録期間を、追加の呼び出しなしで同じレスポンスから得られます。そして、データを一括処理できる場合は、バッチエンドポイントでリクエスト数を減らせます。1回の呼び出しで最大100件のツイート ID または100件のユーザー名を受け付けるため、大量取得でリクエスト量を抑える主要なレバーになります。

API を避けたい場合、古いスクレイパーの経路も依然として存在しますが、動作しなくなることを覚悟してください。オープンソースのスクレイパーが動かなくなった理由 の解説で、そのトレードオフを説明しています。

ツイートIDのみのデータセットをリハイドレートするには? {#how-do-you-rehydrate-a-tweet-id-only-dataset}

リハイドレートとは、ツイート ID のリストを取り、それぞれの現在の内容を取得することを指します。公開の研究用データセットは、完全なツイートではなく ID として配布されます。プラットフォームの規約がツイート本文の再配布を制限しているためで、本文は ID を API に照会した後にはじめて存在します。回収できるのは一部だと考えてください。削除されたツイートや、凍結・現在は非公開のアカウントが投稿したツイートは、もう返ってきません。

一括エンドポイントを使えば、これは安上がりになります。Sorsa の一括ツイートエンドポイントは1回の呼び出しで最大100件の ID を受け付け、完全なツイートオブジェクトを返すため、50,000件の ID ファイルは、50,000回の個別照会ではなく、およそ500リクエストで済みます。

python
import requests

API_KEY = "YOUR_SORSA_API_KEY"
URL = "https://api.sorsa.io/v3/tweet-info-bulk"
HEADERS = {"ApiKey": API_KEY, "Content-Type": "application/json"}

def chunks(seq, n=100):
    for i in range(0, len(seq), n):
        yield seq[i:i + n]

ids = [line.strip() for line in open("tweet_ids.txt") if line.strip()]
rehydrated = []
for batch in chunks(ids, 100):
    r = requests.post(URL, headers=HEADERS, json={"tweet_links": batch}, timeout=30)
    r.raise_for_status()
    rehydrated.extend(r.json().get("tweets", []))

print(f"Recovered {len(rehydrated)} of {len(ids)} tweets")

ID リストが古いほど回収率は下がります。元のツイートが毎年より多く消えていくためです。ID リストがどこから来るのか、そして古いイベントのデータセットがどれだけ残るのかについては、ID リストから古いツイートを回収する ガイドをご覧ください。

学習用にデータセットを構造化しラベル付けする方法 {#how-to-structure-and-label-a-dataset-for-training}

各レコードに安定したスキーマを与え、1行につき1オブジェクトの JSONL にエクスポートします。分類セットにはツイート ID、本文、ラベル、言語、タイムスタンプが必要です。命令チューニング用セットには、命令(instruction)、任意の入力(input)、目標となる出力(output)が必要です。JSONL は、Hugging Face の datasets ライブラリと大半のファインチューニングパイプラインが直接読み込む形式です。

分類レコードと命令レコードは、次のようになります。

json
{"id": "1782368585664626774", "text": "the new build keeps crashing on launch", "label": "negative", "lang": "en", "created_at": "2026-05-01T10:30:00Z"}
json
{"instruction": "Classify the sentiment of this tweet.", "input": "the new build keeps crashing on launch", "output": "negative"}

ラベル付けの前にクリーニングします。ツイート ID で重複排除し、極端に短い、または空のツイートを除き、lang フィールドでフィルターしてセットを対象言語に保ちます。Cardiff NLP の TweetEval の慣例に従い、URL を {{URL}} トークンに、認証されていないユーザー名を {{USERNAME}} に置き換えることで、モデルが特定のリンクやハンドルではなく言語パターンを学習するようにします。

ラベル付けには、スケールする3つのアプローチがあります。評価用に小さなゴールドセットを手作業でラベル付けする。既存の小さなモデルで大部分を事前ラベル付けし、その後人間が修正する(これはゼロからラベル付けするよりはるかに速い)。あるいは命令チューニングなら、ツイートを軸にプロンプトと応答のペアを書く。LLM のファインチューニングガイドは一貫して、生の量より品質を重視します。きれいに整形された数千のペアが、たいてい10倍の規模のノイズの多いセットに勝ります。

最後に、評価を誠実に保つため、学習の前に分割します。よくある分割は、学習80%・検証10%・テスト10%で、再現性のために固定シードでシャッフルします。

python
import json, random

rows = [json.loads(line) for line in open("tweets.jsonl", encoding="utf-8")]
random.seed(42)
random.shuffle(rows)
n = len(rows)
train = rows[: int(0.8 * n)]
val = rows[int(0.8 * n): int(0.9 * n)]
test = rows[int(0.9 * n):]

プラットフォームの規約と倫理はどうなる? {#what-about-platform-terms-and-ethics}

自分のモデルのために公開ツイートを収集するだけなら問題は小さいのですが、データセットを再配布するとなると規約が関わってきます。X の開発者ポリシーによれば、ダウンロード可能なデータセットを含めて第三者とコンテンツを共有する場合、配布できるのは投稿 ID とユーザー ID のみで、完全な本文は配布できません。公開の研究用データセットが ID として配布されるのは、まさにこのためです。

現行の規約は具体的な上限を定めています。X の開発者ポリシーでは、書面による許可なしに、30日間で単一の主体に対して1,500,000件を超える投稿 ID を配布することはできません。一方、非営利の研究のために学術機関を代表して行動する個人は、無制限の数の ID を共有できます。EU デジタルサービス法(DSA)のアクセスを利用する研究者は、別の規定の対象となります。

規約の範囲内にとどまるための実務的なパターンはこうです。収集した完全な本文は自分の学習用に保持し、データセットを公開する場合は、他者が自分で本文を再現できるように、ツイート ID とリハイドレート用スクリプトを公開します。規約は、センシティブな集団やイベントの追跡・監視も禁止しているため、そうした用途からは収集を遠ざけてください。これは一般的なガイダンスであり法的助言ではありません。規約は変わるので、何かを公開する前に現行の X 開発者契約を確認してください。

データセットの収集にはいくらかかる? {#how-much-does-collecting-a-dataset-cost}

コストは量に依存し、またソースがリソース単位で課金するか、リクエスト単位で課金するかに依存します。リソース単位の料金は、レスポンスが返すすべての投稿・すべてのプロフィールに課金するため、ツイートとその作者を取得する呼び出しは2回分課金されます。リクエスト単位の料金は、返る量にかかわらず1回の呼び出しを1単位として数えます。読み取りの多いデータセット取得では、この一点の違いが請求額を決めます。

公式 X API はリソース単位で課金します。1回の投稿読み取りは$0.005、1回のユーザープロフィール読み取りは$0.010で、月間200万回の投稿読み取りが上限です(レートは Twitter API 料金の詳細 にて2026年7月に確認済み)。Sorsa は作者プロフィールを無料で含めて1回の呼び出しにつき1リクエストを課金するため、バッチエンドポイントではデータセット取得が Proプランで1,000ツイートあたり約$0.02から(Starter では$0.049から、Enterprise では$0.018から)、プロフィールは1,000件あたり約$0.01からとなります。

タスク公式 X API(従量課金)Sorsa(Pro、バッチ基準)
1,000ツイート(作者プロフィール込み)$15.00(投稿読み取り1,000回 + ユーザー読み取り1,000回)$0.02から
ツイート ID を1,000件リハイドレート$5.00(投稿読み取り1,000回)$0.02から
100,000ツイートを最初から最後まで収集およそ$500〜$1,500$199の Proプラン1か月分の枠内

Sorsa の数値はバッチ基準を用いています。1リクエストで最大100ツイートまたは200プロフィールを返します。読み取りの多い取得では、フラットなリクエスト単位の請求はリソース単位の料金をはるかに下回り、作者プロフィールは Sorsa 側では一切費用がかかりません。

どの経路が合うかは、一律の正解があるわけではなく、ワークフローによって決まります。

  • 書き込みや投稿: 公式 X API。あらゆる書き込み操作に適した経路です。
  • 非常に少ない読み取り量(月およそ10,000投稿未満): どちらでも機能し、その規模では X の従量課金は安いままです。
  • データセットの構築(読み取りの多い収集にリハイドレートを加えたもの): Sorsa のようなフラットなリクエスト単位の API。同じツイートを取得しても最大50分の1のコストで、作者プロフィールは無料で含まれます。

研究者は 割引価格の学術研究向けアクセス も確認できます。同じ収集コードは、どんなスタックにも移植できます。

実際のデータセット構築例 {#a-real-dataset-build}

金融センチメントのモデルを構築する小さな AI チームは、公式の経路を見積もった後にこの方法にたどり着きました。必要としていたのは、複数の銘柄(ティッカー)に関する最近の英語ツイート約200,000件で、ポジティブ・ネガティブ・ニュートラルのラベル付きです。リソース単位の課金では投稿読み取りだけで約$1,000に達し、作者プロフィールを加えれば、更新前の時点でその2〜3倍になっていたはずでした。しかも更新を計画した途端に、月間200万回の読み取り上限が迫ってきます。収集をフラットなリクエスト単位の API に移したところ、同じ200,000ツイートを Proプラン1か月分の枠のうち約$20で取得できました。投稿読み取りだけで見れば最大50分の1のコスト(約98%削減)で、検索は1リクエストにつき20ツイートを返し、作者プロフィールも無料なので、それらを数に入れればさらに下がります。

構築は小さく保たれました。銘柄ごとに言語フィルター付きのキーワードクエリを走らせて JSONL ファイルに流し込み、小さな分類器が行を事前ラベル付けし、アナリストがサンプルを修正しました。URL とハンドルはトークンに正規化し、セットは固定シードで80・10・10に分割しました。後に古い公開イベントのデータセットを拡張したくなったときは、その ID リストを100件ずつのバッチでリハイドレートし、元のツイートの一部がその後削除されていることを受け入れました。このチームが得た教訓は「順序」でした。ラベル体系とクエリを先に定義することです。高くつく間違いは API の請求ではなく、スキーマ変更後の再収集だからです。

よくある質問 {#faq}

2026年でもデータセット用のツイートを収集できる?

はい、ただし古いツールは使えません。無料の Twitter API プランは2023年に終了し、snscrape や twint のようなスクレイパーは現在のプラットフォームに対してもう動きません。実用的な規模での新規収集は今や、検索とタイムラインの結果を返す有料のデータ API を経由し、結果をページネーションで順に取得してファイルに書き込みます。タスクに既に合致する公開データセットがあれば、それも選択肢として残ります。

出来合いのTwitterデータセットはどこで手に入る?

Hugging Face と Kaggle が主要な公開ツイートデータセットをホストしています。Sentiment140 は感情ラベル付きの約160万件のツイートを収録し、TweetEval ベンチマークは皮肉・ヘイト・感情など7つの分類タスクをカバーします。多くの学術データセットは完全な本文ではなくツイート ID として配布されるため、手元にツイート本文がそろう前に、ID を API に照会してリハイドレートします。

ツイートIDはどうリハイドレートする?

リハイドレートは、ツイート ID のリストについて現在の内容を照会します。一括エンドポイントを使えば安上がりです。Sorsa のような読み取り専用 API は1回の呼び出しで最大100件の ID を受け付け、完全なツイートオブジェクトを返すため、50,000件の ID ファイルは約500リクエストになります。削除された、または凍結・非公開のアカウントが投稿したツイートはもう返らないため、回収できるのは一部だと考えてください。

モデルをファインチューニングするにはツイートが何件必要?

タスクによりますが、量より品質が重要です。狭い分類や命令追従のタスクなら、きれいに整形され、正しくラベル付けされた数千件の例だけでも、モデルを十分に鍛えられることが多いです。一方、その10倍の規模のノイズの多いセットのほうが効果が小さいこともあります。目的を定義し、まず小さく高品質なセットをラベル付けし、評価がより多くのカバレッジを必要とすると示した場合にのみ拡大しましょう。

Twitterデータセットの構築・共有は合法?

自分のモデルのために公開ツイートを収集することは概ね許可されていますが、再配布は制限されています。X の開発者ポリシーは、公開データセットで共有できるのを投稿 ID とユーザー ID のみとし、完全なツイート本文は認めず、単一の主体につき30日で1,500,000件の ID という上限と、学術機関向けの例外を設けています。生の本文ではなく ID とリハイドレート用スクリプトを公開し、公開前に現行の規約を確認してください。

データセットの構築に公式 X API は必要?

いいえ。公式 X API が必要なのは、投稿のような書き込みアクションのときだけです。公開ツイートとプロフィールの収集には、Sorsa API のような読み取り専用の代替が、単一の ApiKey ヘッダーを用い、ツイート単位ではなくリクエスト単位で課金し、作者プロフィールを無料で含めます。Proプランのバッチ料金なら1,000ツイートあたり約$0.02から利用でき、クレジットカード不要・100回分の無料リクエストが実際のテスト実行をカバーします。

始め方 {#getting-started}

データセットの規模を見積もる最も速い方法は、パイプラインを書く前にクエリを実行することです。ブラウザ版の API playground を開き、自分の検索コマンドで検索を実行し、JSONL にマッピングする JSON フィールドを確認しましょう。クエリが良さそうなら、上記の収集スクリプトをプロジェクトに落とし込み、ファイルを指定します。

Sorsa は100回分の無料リクエストから始められます。1回限り・クレジットカード不要・有効期限なしで、40個のエンドポイントすべてで有効です。テスト中に最大10,000ツイートをリハイドレートしたり、最大20,000プロフィールを取得したりするのに十分です。スケールする準備ができたら、リクエスト単位の料金プラン を利用できます。バッチエンドポイントで1,000ツイートあたり約$0.02から、一律で毎秒20リクエスト、開発者アカウントの審査待ちもありません。

監修:Keksich(Sorsa創業者、マーケター兼X APIリサーチャー)

本ガイドは、稼働中の Sorsa API とそのドキュメントを運用する当チームの実地の作業に加え、執筆時点で確認した公開データセットとプラットフォーム規約に基づいています。コンテンツ再配布の上限は X の開発者ポリシーから、公開データセットと正規化の慣例は Hugging Face の TweetEval データセットから読み取り、公式 X API のリソース単位のレートは現行の公開された内訳と突き合わせて確認しました。当チームの詳細は about ページ にあります。2026年7月確認。