Raise the clustering to 100 groups
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -462,3 +462,21 @@
|
||||
平台輸出過濾非隨機地排除了語料中最核心的一批歌,此
|
||||
現象本身列入論文限制討論。標註步驟已入庫的兩次執行
|
||||
重製量約 43%,處置待議。
|
||||
- **分群組數自 50 改為 100**:k=50 下
|
||||
出現數個「雜物櫃組」——組內語意發散、medoid 只是折衷
|
||||
詞,編碼實測幾乎不用(`mutual-individuality` 158 詞、
|
||||
僅用於 2% 的歌;`fantasy-and-imagination` 232 詞含
|
||||
籃球、海灘、神性意象)。k=30 更劣(最大組 491 詞、
|
||||
組內一致 0.41)。改 linkage 無用:三種 linkage 於各個
|
||||
k 實測,Ward 的組內一致性均最高,average 與 complete
|
||||
反而產生吞噬半數語料的巨組。診斷為壓縮比過高——語料
|
||||
的主題多樣性超過 50 種,非演算法選擇問題。裁定:k
|
||||
取 100,雜物櫃組於此始裂解為有主題的組。實測 148 首
|
||||
探測:101 碼下詞彙表外的
|
||||
碼由 3 降為 0、未使用碼由多個降為 1、每首碼數中位數
|
||||
12→16、`women-power` 命中率 13%→9%(碼變細後邊緣
|
||||
歌不再被歸入)。代價:每次編碼執行成本由 $3.96 升至
|
||||
約 $7.0。
|
||||
- **零使用的碼據實報告,不事後改名**:medoid 命名對
|
||||
大而異質的組必然失準,該碼在結果中呈現為零使用即是
|
||||
儀器的誠實紀錄;改名等於在看過結果後調整儀器。
|
||||
|
||||
+18
-6
@@ -37,12 +37,24 @@ Run、Song,一列一筆出現,依三欄排序),供收斂軌跡分析;
|
||||
- **嵌入**:`sentence-transformers/all-mpnet-base-v2`
|
||||
(釘定 revision),關鍵字的連字號先還原為空格再編碼,
|
||||
輸出 768 維向量並 L2 正規化。
|
||||
- **分群**:階層式聚合分群(Ward linkage),k=50。
|
||||
向量既已正規化,歐氏距離與餘弦相似度單調對應,Ward
|
||||
在保持語意距離的同時給出大小平衡的分割。
|
||||
- **分群**:階層式聚合分群(Ward linkage),k=100。
|
||||
向量既已正規化,歐氏距離與餘弦相似度單調對應;三種
|
||||
linkage 實測比較,Ward 於各個 k 的組內一致性均最高
|
||||
(average 與 complete 皆產生吞噬半數語料的巨大異質
|
||||
組)。
|
||||
- **組數的取捨**:k 太小則壓縮比過高,樹上層被迫併入
|
||||
不相干的詞,組雖大而無主題(k=30 最大組 491 詞、
|
||||
組內一致性 0.41,成員橫跨籃球、海灘、外星人綁架);
|
||||
k 太大則人工難以通覽。定於 100,理由是實測顯示雜物櫃
|
||||
組於此始裂解為有主題的組,且編碼實測未見碼數過多的
|
||||
副作用(詞彙表外的碼歸零、僅一個碼零使用)。
|
||||
- **組名**:取 medoid——與該組中心(成員向量均值後
|
||||
正規化)餘弦相似度最高的成員詞。組名因此必為模型
|
||||
自己產出過的關鍵字,非任何人事後撰寫。
|
||||
自己產出過的關鍵字,非任何人事後撰寫。已知限制:
|
||||
組越大越異質時,medoid 只是折衷詞,可能代表不了組內
|
||||
內容(實測 `mutual-individuality` 組內一致 0.70 而
|
||||
編碼從未使用);此類碼於結果中呈現為零使用,據實
|
||||
報告,不事後改名。
|
||||
- **取捨紀錄**:曾以 LLM 單發收斂(merge/cap 兩步)
|
||||
實作本步,四種模型六次執行全部無法維持完整分割,
|
||||
已棄用(詳見 `decision-log.md` 2026-08-05;棄用的
|
||||
@@ -62,8 +74,8 @@ Run、Song,一列一筆出現,依三欄排序),供收斂軌跡分析;
|
||||
|
||||
### women-power 的注入
|
||||
|
||||
定案詞彙表為 50 個分群組名再加上 `women-power` 一詞,共
|
||||
51 個碼。`women-power` 是研究者任意決定的先驗主題(即本
|
||||
定案詞彙表為 100 個分群組名再加上 `women-power` 一詞,
|
||||
共 101 個碼。`women-power` 是研究者任意決定的先驗主題(即本
|
||||
論文的主題本身),不由資料產生,屬揭露的儀器介入。該詞
|
||||
於執行時以 `--extra-keyword` 明示加入,不寫死在程式裏
|
||||
——研究者的介入因此每次都出現在重現命令上,而非無聲
|
||||
|
||||
@@ -97,8 +97,9 @@
|
||||
thematic keywords:前導研究三粒度比較(keywords 過碎、
|
||||
themes 過早抽象)之繼承,於執行前鎖定,防止事後擇優。
|
||||
2. **詞彙表建構(步驟 2)**:兩次執行的關鍵字取聯集去重
|
||||
後,以句向量模型嵌入、階層式聚合分群,k=50,組名取
|
||||
medoid;進池與分群為同一個確定性子命令。完整分割由演算法
|
||||
後,以句向量模型嵌入、階層式聚合分群,k=100,組名取
|
||||
medoid;進池與分群為同一個確定性子命令。完整分割由
|
||||
演算法
|
||||
結構保證。頻次不入收斂:頻率的分析角色由步驟 3 編碼
|
||||
承擔;池中頻次含跨執行噪音。
|
||||
3. **編碼(步驟 3)**:以定稿詞彙表對全部歌曲 2+1 編碼
|
||||
@@ -110,7 +111,7 @@
|
||||
扭曲,不作主結果。
|
||||
|
||||
**先驗主題詞 `women-power` 併入詞彙表**:定案詞彙表為
|
||||
50 個分群組名再加上 `women-power`,共 51 個碼。該詞是
|
||||
100 個分群組名再加上 `women-power`,共 101 個碼。該詞是
|
||||
研究者任意決定的先驗主題,即本研究的論文主題本身,不由
|
||||
資料產生,屬據實揭露的儀器介入。不另設單目標篩選軌,理由是
|
||||
讓研究者的主題詞與模型自己收斂出的類別在同一份提示詞、
|
||||
@@ -136,7 +137,7 @@
|
||||
|---|---|---|---|
|
||||
| 0 | 基礎建設:git init、目錄結構、.gitignore、決策日誌、runner script(含 Batch API)、codebook v0 骨架 | script + 討論 | 7/30–7/31 |
|
||||
| 1 | 資料準備:`run_llm` 改走統一設定 → `build-db`(解析榜單成 songs/chart_entries/artists/song_artists)→ `import-lyrics`(pilot 2018–2025)→ `fetch-lyrics`(2016–17 與缺漏,Lyrics.ovh / LRCLIB)→ `fetch-artists`(Wikidata 快照)→ `export-llm-input` | 子命令 | 7/31–8/3 |
|
||||
| 2 | 自然編碼管線:tag ×2 進池 → 詞向量分群 k=50 → 併入 women-power → 詞彙表定稿 → code 2+1(全 883 首,附引述) | API + script | 8/4–8/7 |
|
||||
| 2 | 自然編碼管線:tag ×2 進池 → 詞向量分群 k=100 → 併入 women-power → 詞彙表定稿 → code 2+1(全 883 首,附引述) | API + script | 8/4–8/7 |
|
||||
| 3 | 黃金標準:依 codebook 人工逐首判定 genuine/peripheral/fake,附引用歌詞證據表(LLM 只做摘錄,不給判定建議);先以 10–15 首校準樣本試編並修訂 codebook 後凍結;同批校準樣本實測 Sonnet 4.6 vs Opus 5 一致率 | 人工 + script 輔助 | 8/5–8/9 |
|
||||
| 4 | 受控比較(盲點實驗):條件 A(詞彙層提示)vs 條件 B(框架感知提示),各 2+1,對照黃金標準計算假陽/假陰率 | API | 8/8–8/11 |
|
||||
| 4' | 映射分析:自然編碼結果(第 4 步)與黃金標準交叉表;軌跡對映 vs 直接編碼的扭曲診斷(分析方法先寫入 methodology.md 再看結果) | script | 與 4 並行 |
|
||||
|
||||
+2
-1
@@ -31,5 +31,6 @@ $3/$15、opus-4-6 $5/$25、opus-5 與 fable-5 $10/$50)
|
||||
| 2026-08-05 | 03-01-code | run1 | claude-sonnet-4-6 | msgbatch_01L7VepTxSNz5vruvzzjuL2c | 6 分 36 秒 | 1,247,264 | 492,730 | $5.57 | 36 首輸出遭內容過濾攔阻,待修訂重跑 |
|
||||
| 2026-08-05 | 03-01-code | 引述減量實驗(36 首)| claude-sonnet-4-6 | msgbatch_01Hskdhi2DkudYmgZhhgFts7 | 3 分 51 秒 | 56,458 | 11,074 | $0.17 | 實驗:每碼一行引述,36 首全數通過過濾;歸檔不入 repo |
|
||||
| 2026-08-05 | 03-01-code | run1 | claude-sonnet-4-6 | msgbatch_01GG5Ez9KT1pPwtQaY4sW7tv | 4 分 35 秒 | 1,293,724 | 269,166 | $3.96 | 過濾零攔阻;song-168、song-590 因餘額用盡失敗,song-775 拒答 |
|
||||
| 2026-08-05 | 03-01-code | 101 碼樹狀探測(148 首)| claude-sonnet-4-6 | msgbatch_017jo3E5gWVks9b39iWMTqz3 | 2 小時 11 分 | 385,270 | 79,690 | $0.87 | 實驗:k=100 葉碼+women-power;零違規碼; 歸檔不入 repo |
|
||||
|
||||
累計支出:$43.40。
|
||||
累計支出:$44.27。
|
||||
|
||||
@@ -40,7 +40,6 @@ from typing import Any
|
||||
from ..utils import format_duration
|
||||
|
||||
MODEL: str = "sentence-transformers/all-mpnet-base-v2"
|
||||
DEFAULT_CLUSTERS: int = 50
|
||||
CLUSTER_EXTRA_MESSAGE: str = (
|
||||
"cluster-keywords requires the optional \"cluster\""
|
||||
" dependency group; install it with"
|
||||
@@ -101,8 +100,9 @@ def parse_args(argv: list[str] | None) -> argparse.Namespace:
|
||||
"--revision", default=None,
|
||||
help="the model revision to pin (default: unpinned)")
|
||||
parser.add_argument(
|
||||
"--clusters", type=int, default=DEFAULT_CLUSTERS,
|
||||
help=f"the number of clusters (default {DEFAULT_CLUSTERS})")
|
||||
"--clusters", type=int, required=True,
|
||||
help="the number of clusters; required, so that the\n"
|
||||
"group count is stated on every invocation")
|
||||
parser.add_argument(
|
||||
"--extra-keyword", dest="extra_keywords", action="append",
|
||||
default=None,
|
||||
|
||||
@@ -478,6 +478,15 @@ class TestClusterKeywords(unittest.TestCase):
|
||||
["a-center", "aaa-extra", "b-middle", "zzz-extra"])
|
||||
self.assertEqual(keywords, sorted(keywords))
|
||||
|
||||
def test_missing_clusters_option_rejected(self) -> None:
|
||||
"""Test that omitting --clusters fails the run."""
|
||||
with self.assertRaises(SystemExit) as caught, \
|
||||
redirect_stderr(io.StringIO()):
|
||||
cluster_keywords.parse_args(
|
||||
[str(self.__run1), str(self.__run2),
|
||||
str(self.__output_dir)])
|
||||
self.assertNotEqual(caught.exception.code, 0)
|
||||
|
||||
def test_duplicate_extra_keyword_rejected(self) -> None:
|
||||
"""Test that repeating the same ``--extra-keyword`` value
|
||||
fails the run without writing any output file."""
|
||||
|
||||
Reference in New Issue
Block a user