Pure-math text intelligence engine for Japanese — vocabulary richness, contamination detection, writing habit analysis, character voice fingerprinting
Project description
japhrase
辞書もLLMも使わずに、テキストからフレーズを見つける。
pip install japhrase
2行で全機能デモ
import japhrase
japhrase.run_demo()
内蔵の例文でフレーズ抽出・語彙多様性・テキスト複雑度・分布比較・コロケーション分析・汚染検出・品質チェックが順に実行される。何も用意しなくていい。
コピペで動く使用例
以下のコードは すべて1ブロックで完結 する。コピペしてそのまま動く。ファイルもデータも不要。
フレーズ抽出(辞書なし・形態素解析なし)
from japhrase import PhraseExtractor
text = """ChatGPTの登場により生成AIが注目を集めている。
生成AIはテキストだけでなく画像生成にも使われる。
大規模言語モデルは生成AIの中核技術である。
生成AIの倫理的課題について議論が活発化している。
企業における生成AIの導入事例が増加している。""" * 5
sentences = [s.strip() for s in text.split("。") if s.strip()]
df = PhraseExtractor(min_count=2, min_length=2, max_length=10, selection=0, verbose=0).extract(sentences)
print(df[["seqchar", "freq"]].head(3))
seqchar freq
0 生成AI 25.0
2 ChatGPTの登場に 5.0
18 大規模言語モデルは生成 5.0
語彙の豊かさを比較
from japhrase import StylometryAnalyzer
stylo = StylometryAnalyzer()
text_a = "朝靄の中を歩いていると、足元で小さな花が揺れた。名前は知らない。淡い紫色の花弁が露を含んで光っている。道の先に古い石橋が見えた。"
text_b = "男は歩いた。男は止まった。男はまた歩いた。男は見た。男は聞いた。男は歩いた。"
for label, t in [("豊かな文", text_a), ("単調な文", text_b)]:
r = stylo.analyze_advanced_diversity(t)
print(f"{label}: Hapax比={r['hapax_ratio']:.2f} Simpson={r['simpsons_d']:.4f}")
豊かな文: Hapax比=0.97 Simpson=0.9995
単調な文: Hapax比=0.68 Simpson=0.9692
2つのテキストの語彙分布を比較
from japhrase import DistributionComparator
from collections import Counter
comp = DistributionComparator()
result = comp.compare(
Counter({"騎士": 10, "剣": 8, "王城": 5}),
Counter({"研究": 12, "実験": 9, "データ": 7}),
)
print(f"JS距離: {result.jsd:.4f} (0=同一, 1=完全に別)")
JS距離: 1.0000 (0=同一, 1=完全に別)
語の結びつきの強さを測る
from japhrase import CollocationScorer
scorer = CollocationScorer()
cs = scorer.score_phrase("生成AI", 45, "生成AIが注目されている。" * 50)
print(f"PMI={cs.pmi:.1f} t-score={cs.t_score:.1f} Log-Dice={cs.log_dice:.1f}")
PMI=3.5 t-score=6.1 Log-Dice=13.8
テキストの複雑度を測る
from japhrase import ComplexityAnalyzer
cx = ComplexityAnalyzer()
for label, t in [("多様な文章", "朝靄の中を歩いていると、足元で小さな花が揺れた。名前は知らない。淡い紫色の花弁が露を含んで光っている。"),
("繰り返し", "男は歩いた。" * 20)]:
r = cx.analyze(t)
print(f"{label}: 圧縮率={r['compression_ratio']:.3f} 情報率={r['information_rate']:.3f}")
多様な文章: 圧縮率=0.869 情報率=0.961
繰り返し: 圧縮率=0.092 情報率=0.050
テキストの汚染を検出
from japhrase.contamination import scan
profile = scan("正常な文章。\n’文字化け。\n「閉じない台詞")
print(f"汚染スコア: {profile.overall}/100")
print(profile.explain())
汚染スコア: 15/100
⚠️ 汚染スコア: 15/100
■ エンコーディング (55/100, 1件)
L2: mojibakeパターン: '’'
💡 文字化け箇所を正しい文字に置換してください。
複数テキストの一括汚染チェック
from japhrase.contamination import batch_scan
texts = {
"1章": "正常なテキスト。問題のない文章が続きます。特に異常はありません。",
"2章": "’文字化け。「閉じない括弧。重複文。重複文。重複文。重複文。重複文。",
"3章": "正常なテキスト。こちらも問題ありません。普通の文章です。",
}
result = batch_scan(texts)
print(f"全クリーン: {result.all_clean}")
for key, p in result.profiles.items():
print(f" {key}: スコア={p.overall}/100 クリーン={p.is_clean()}")
全クリーン: False
1章: スコア=0/100 クリーン=True
2章: スコア=23/100 クリーン=False
3章: スコア=0/100 クリーン=True
時系列で語彙の変化を追跡
from japhrase import TemporalAnalyzer
ch1 = "騎士が剣を抜いた。王城の門が開いた。騎士は走った。剣が光った。" * 10
ch2 = "研究室でデータを確認した。実験の結果を記録した。論文を読んだ。" * 10
ch3 = "騎士は剣を収めた。王城に平和が戻った。研究が進んだ。" * 10
ta = TemporalAnalyzer()
result = ta.analyze_series([ch1, ch2, ch3], labels=["1章", "2章", "3章"])
print(f"語彙飽和度: {result['vocab_saturation']:.2f}")
語彙飽和度: 1.00
テキスト類似度(コピペ検出)
from japhrase import SimilarityAnalyzer
texts = [
"生成AIが注目を集めている。大規模言語モデルの進化が著しい。",
"生成AIの技術が注目されている。言語モデルが急速に進化している。",
"今日は天気がよい。散歩に出かけた。公園で花を見た。",
]
analyzer = SimilarityAnalyzer(method='jaccard')
matrix = analyzer.compare_texts(texts)
print(matrix)
text_1 text_2 text_3
text_1 1.000000 0.166667 0.0
text_2 0.166667 1.000000 0.0
text_3 0.000000 0.000000 1.0
text_1 と text_2 は類似(0.17)、text_3 は完全に別(0.0)。
何をするツールか
日本語テキストの中から、繰り返し出現するフレーズを統計だけで検出する。MeCab も辞書ファイルも外部 AI も要らない。テキストを入れれば、そこに何度も現れているフレーズが出てくる——それが既知語であろうと、辞書に載っていない新語・造語・専門用語であろうと関係ない。
N-gram による頻度抽出
テキストを「連続する N 文字」の断片(N-gram)に分解し、出現頻度を数える。
from japhrase import PhraseExtractor
text = """ChatGPTの登場により生成AIが注目を集めている。
生成AIはテキストだけでなく画像生成にも使われる。
大規模言語モデルは生成AIの中核技術である。
生成AIの倫理的課題について議論が活発化している。
企業における生成AIの導入事例が増加している。""" * 5
sentences = [s.strip() for s in text.split("。") if s.strip()]
extractor = PhraseExtractor(min_count=2, max_length=10, min_length=2, verbose=0)
df = extractor.extract(sentences)
print(df[["seqchar", "freq"]].head(5))
「生成AI」「大規模言語モデル」は見つかる。しかし「ている」「である」のような、どんなテキストにも現れる意味のないフレーズも一緒に出てくる。N-gram の頻度だけでは、意味のある結合と偶然の並びを区別できない。
PMI による洗練
PMI(自己相互情報量)は「2つの要素が偶然一緒に現れる確率」と「実際に一緒に現れた頻度」の比を測る。
from japhrase import PhraseExtractor
text = """ChatGPTの登場により生成AIが注目を集めている。
生成AIはテキストだけでなく画像生成にも使われる。
大規模言語モデルは生成AIの中核技術である。
生成AIの倫理的課題について議論が活発化している。
企業における生成AIの導入事例が増加している。""" * 5
sentences = [s.strip() for s in text.split("。") if s.strip()]
extractor = PhraseExtractor(min_count=2, use_pmi=True, verbose=0)
df = extractor.extract(sentences)
print(df[["seqchar", "freq"]].head(5))
PMI が高いフレーズは、構成要素が偶然隣り合っただけでは説明できないほど頻繁に共起している。「生成」と「AI」がこれほど一緒に出現するのは、それが1つの意味単位だからだ。
分岐エントロピーによる境界検出
さらに分岐エントロピーを加えると、フレーズの自然な切れ目を特定できる。「あるフレーズの次にどんな文字が来るか」の多様性を測り、多様性が急に上がる位置をフレーズの境界とみなす。
from japhrase import PhraseExtractor
text = """ChatGPTの登場により生成AIが注目を集めている。
生成AIはテキストだけでなく画像生成にも使われる。
大規模言語モデルは生成AIの中核技術である。
生成AIの倫理的課題について議論が活発化している。
企業における生成AIの導入事例が増加している。""" * 5
sentences = [s.strip() for s in text.split("。") if s.strip()]
extractor = PhraseExtractor(min_count=3, use_pmi=True, use_branching_entropy=True, verbose=0)
df = extractor.extract(sentences)
print(df[["seqchar", "freq"]].head(5))
N-gram が「繰り返されているもの」を広く拾い、PMI が「意味のある結合」だけを残し、分岐エントロピーが「切れ目」を正確にする。この3層が japhrase のコアである。
プリセット
テキスト種別ごとに最適化されたパラメータセット(Optuna による実験的最適化済み)。
from japhrase import PhraseExtractor
extractor = PhraseExtractor.preset('sns') # SNS/Twitter(短文・高頻度)
extractor = PhraseExtractor.preset('news') # ニュース(専門用語重視)
extractor = PhraseExtractor.preset('novel') # 小説(繰り返し表現・長め)
extractor = PhraseExtractor.preset('report') # 論文/レポート(定型・学術用語)
print(extractor) # パラメータ確認
デモで全機能を体験する
Python を起動して2行書くだけで、全7機能が内蔵例文で実行される。
import japhrase
japhrase.run_demo()
個別にデモもできる:
from japhrase import PhraseExtractor, StylometryAnalyzer, ComplexityAnalyzer
from japhrase import DistributionComparator, CollocationScorer
PhraseExtractor.demo() # フレーズ抽出だけ
StylometryAnalyzer.demo() # 語彙多様性
ComplexityAnalyzer.demo() # テキスト複雑度
DistributionComparator.demo() # 分布比較
CollocationScorer.demo() # コロケーション分析
コアの上に積み上げた分析機能
フレーズ抽出エンジンを土台として、以下の統計分析機能を提供する。すべて pip install japhrase だけで使える。
分布比較(2テキスト間の語彙の違い)
from japhrase import DistributionComparator
from collections import Counter
comp = DistributionComparator()
result = comp.compare(
Counter({"騎士": 10, "剣": 8, "王城": 5}),
Counter({"研究": 12, "実験": 9, "データ": 7}),
)
print(f"JS距離: {result.jsd:.4f}")
for kr in sorted(result.keyness_results, key=lambda x: x.log_likelihood, reverse=True)[:3]:
print(f" {kr.term}: {kr.direction} (log-likelihood={kr.log_likelihood:.1f})")
JS距離: 1.0000
騎士: overuse (log-likelihood=19.0)
研究: underuse (log-likelihood=17.4)
剣: overuse (log-likelihood=14.6)
JS距離(Jensen-Shannon Divergence)は対称的で有界(0〜1)。対数尤度比(G²)はカイ二乗より疎データに強い。Effect Size(Log Ratio)は「有意かどうか」ではなく「どれだけ違うか」を測る。
コロケーション分析(語の結びつきの強さ)
from japhrase import CollocationScorer
text = "生成AIが注目されている。生成AIの技術が進んでいる。" * 50
scorer = CollocationScorer()
cs = scorer.score_phrase("生成AI", 45, text)
print(f"PMI={cs.pmi:.1f} t-score={cs.t_score:.1f} Log-Dice={cs.log_dice:.1f}")
| 指標 | 何に強いか |
|---|---|
| PMI | レアだが意味のある結合を発見する(低頻度に敏感) |
| t-score | 高頻度で安定した結合を発見する(PMI の逆) |
| Log-Dice | コーパスの大きさに影響されない(最も安定) |
| MI³ | PMI の低頻度バイアスを数学的に補正する |
| Delta-P | 方向性がある結合を測る(A→B と B→A は非対称) |
共起語分析
特定のキーワードの周辺に、統計的に特異な頻度で出現する語を抽出する(CooccurrenceAnalyzer)。キャラクター分析や製品レビュー分析に使える。大量テキスト向け。
語彙多様性(計量言語学)
from japhrase import StylometryAnalyzer
stylo = StylometryAnalyzer()
text_a = "朝靄の中を歩いていると、足元で小さな花が揺れた。名前は知らない。淡い紫色の花弁が露を含んで光っている。道の先に古い石橋が見えた。"
text_b = "男は歩いた。男は止まった。男はまた歩いた。男は見た。男は聞いた。男は歩いた。"
for label, t in [("豊かな文章", text_a), ("単調な文章", text_b)]:
adv = stylo.analyze_advanced_diversity(t)
print(f"{label}: Hapax比={adv['hapax_ratio']:.2f} MATTR={stylo.analyze_mattr(t)['mattr']:.3f}")
| 指標 | 何を測るか | 読み方 |
|---|---|---|
| Hapax比 | 一度しか使わなかった語の割合 | 高い = 同じ語に頼っていない |
| MATTR | テキスト長に依存しない語彙多様性 | 高い = 長文でも語彙が豊か |
| Simpson's D | 同じ語に2回当たる確率の逆数 | 1に近い = 多様 |
| Brunet's W / Honoré's R | 長文で崩壊しない多様性指標 | 長編小説の比較に使える |
| Heaps' Law (β) | 読み進めるほど新語がどれだけ出るか | 高い = 最後まで新語が出続ける |
テキスト複雑度・情報密度
from japhrase import ComplexityAnalyzer
cx = ComplexityAnalyzer()
for label, t in [("多様な文章", "朝靄の中を歩いていると、足元で小さな花が揺れた。名前は知らない。淡い紫色の花弁が露を含んで光っている。"),
("繰り返し", "男は歩いた。" * 20)]:
r = cx.analyze(t)
print(f"{label}: 圧縮率={r['compression_ratio']:.3f} 情報率={r['information_rate']:.3f}")
| 指標 | 何を測るか | 読み方 |
|---|---|---|
| 圧縮率 | zlib で圧縮したサイズ比 | 低い = 同じパターンの繰り返しが多い |
| 情報率 | 各文が提供する新情報の割合 | 低い = 前の文と同じことを言っている |
| 語彙密度 | 内容語 / 全語の比率 | 低い = 機能語(助詞等)が多く冗長 |
| パープレキシティ | N-gram の予測困難度 | 高い = 多様で予測しにくい文章 |
テキスト品質
| 機能 | 説明 | 使い方 |
|---|---|---|
| TextVariantDetector | 表記ゆれ検出 | サーバー/サーバ、出来る/できる を発見 |
| WritingHabitDetector | 書き癖検出 | 高頻度×低PMI = 無意識の繰り返しを発見 |
| Summarizer | 統計的要約 | LLM不要・ハルシネーションなしでテキスト圧縮 |
汚染検出
テキストの破損(文字化け・コピペ重複・句読点の揺れ等)を8軸で検出する。
from japhrase.contamination import scan, quick_check, batch_scan, compare
# ワンライナー(True=汚染あり, False=クリーン)
print(quick_check("’文字化け。「閉じない。重複文。重複文。重複文。重複文。")) # → True
print(quick_check("正常なテキスト。問題のない文章です。")) # → False
# 詳細スキャン
profile = scan("’文字化け。「閉じない括弧。重複文。重複文。重複文。重複文。重複文。")
print(profile.explain())
# 2テキスト比較
r = compare("正常なテキスト。問題のない文章。", "’文字化け。「閉じない括弧")
print(r.report()[:100])
その他
- テキスト類似度: Jaccard / Levenshtein / コサイン(
SimilarityAnalyzer) - 時系列分析: 語彙飽和度・バースト検出・MATTRトレンド(
TemporalAnalyzer) - 執筆ワークフロー: 公開前品質ゲート・話数間推移・キャラ文体指紋・A〜E健康診断(
japhrase.applied) - NMF文書ベクトル化 / ストリーミング処理 / パラメータ自動最適化 / 自動インサイト生成
ファイルからの読み込み
from japhrase import PhraseExtractor
# テキストファイル(エンコーディング自動検出: UTF-8 / Shift-JIS / EUC-JP)
df = PhraseExtractor.from_file("input.txt")
# CSV(列指定)
df = PhraseExtractor.from_file("data.csv", column="text")
パラメータ一覧
from japhrase import PhraseExtractor
extractor = PhraseExtractor(
min_count=6, # 最小出現回数(小さいと計算時間が増える)
max_length=16, # フレーズの最大文字数
min_length=4, # フレーズの最小文字数
threshold_originality=0.5, # 類似フレーズ除去の閾値(0.0〜1.0)
use_pmi=True, # PMI で意味的結合を評価
use_branching_entropy=True, # 分岐エントロピーで境界を検出
knowns=["既知語1"], # 優先的に抽出したい既知語
verbose=1, # 進捗表示(0:非表示, 1:表示)
)
CLI
japhrase --help # コマンド一覧
japhrase extract --help # フレーズ抽出の引数とオプション
japhrase stats --help # 統計出力の形式指定
japhrase check --help # 文書品質チェック
japhrase detect-habits --help # 書き癖検出
help() で調べる
全クラス・全関数に docstring がある。
from japhrase import PhraseExtractor
help(PhraseExtractor.extract) # 引数・戻り値・使用例
from japhrase import StylometryAnalyzer, ComplexityAnalyzer
help(StylometryAnalyzer) # 語彙多様性(7指標)
help(ComplexityAnalyzer) # テキスト複雑度
from japhrase.contamination import scan
help(scan) # 8軸汚染スキャン
テスト
pytest # 290件以上
pytest --cov=japhrase # カバレッジ付き
English Summary
japhrase finds phrases in Japanese text without a dictionary or LLM. It scans for recurring N-gram patterns, then uses PMI (pointwise mutual information) to separate meaningful collocations from noise — "生成AI" ranks high because its components co-occur far more than chance predicts, while "である" ranks low. Branching entropy further refines phrase boundaries. On top of this core: text similarity, distribution comparison (JSD, G², keyness), collocation scoring (6 metrics), vocabulary richness (7 metrics), text complexity, and more. Pure math, no external AI, 290+ tests, numpy/scipy only.
ライセンス
MIT License — Takeshi SHIMIZU
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file japhrase-0.3.11.tar.gz.
File metadata
- Download URL: japhrase-0.3.11.tar.gz
- Upload date:
- Size: 331.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6baa481c328c47d4a93e98d9207fae50af28926ecb52400a9327b567a2b4d0ee
|
|
| MD5 |
364164c6c1db449dbd32e359bbc3bfff
|
|
| BLAKE2b-256 |
e7447214ae8c251691e942da41a5439fef8758d2738b8794bb74c230ac744608
|
File details
Details for the file japhrase-0.3.11-py3-none-any.whl.
File metadata
- Download URL: japhrase-0.3.11-py3-none-any.whl
- Upload date:
- Size: 288.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a4e64b99f611eecd562e3f35a35f793fe6520f6613974dad2f2daf08f11b8e71
|
|
| MD5 |
817fb18757d7edf76d86838388a437cd
|
|
| BLAKE2b-256 |
369752210d3aca477defd53aeebb91f92cf7ce33d0dcc7aeafc69db5453e31fd
|