跳轉到內容

一致性漂移與再校準輪次

Potato 在 /admin/iaa 上按已完成條目的視窗計算一致性,在一致性低於項目基線時給出提示,並讓編碼者重新回到培訓階段。

Potato 在先後相繼的已完成條目視窗中計算編碼者間一致性,因此近期編碼品質的下滑會在一致性報告上表現為一個偏低的視窗,而不會被平均進一個全項目的數字裡。全項目係數把第一週的編碼和最後一週的編碼混在一起,一個近期工作已經走樣的團隊仍可能報告一個可以接受的 α。/admin/iaa 上的 Agreement over time 部分逐個視窗顯示每個標註方案的係數,並在最近一個視窗比項目基線低出設定的比例時給出再校準提示。隨後,再校準輪次會讓編碼者重新做一遍培訓條目,並用已知的正確答案為編碼者的回答評分。時間線和再校準輪次從 Potato v2.9.0 起就已提供,時間線預設開啟。

這裡的漂移(drift)指在一項研究的進行過程中,編碼者應用碼本的方式逐漸發生的變化。隨著新的邊緣案例出現,每名編碼者各自形成對某條定義的私人理解,漂移就逐漸累積起來。編碼開始前的一次性編碼者間信度檢驗無法發現漂移。Hennessy、Bleakley 和 Ellithorpe(2022)引用了 Lacy 等人(2015)的一段話,Lacy 等人寫道:"the intercoder reliability check should occur with study content as it is coded."(編碼者間信度檢驗應當在研究內容被編碼的同時進行。)同樣的問題也適用於標註指南隨標籤集擴大而不斷變化的機器學習標註團隊。本頁討論研究進行過程中的一致性,而時間片段上的一致性討論標註者在音訊和影片中標記起止時間的情況。

視窗邊界與條目時間戳

一致性屬於跨編碼者的某個條目,而不屬於某一名編碼者的答案。因此,Potato 把每個條目放進包含該條目最後一名編碼者完成時刻的那個視窗。那個時刻是該條目第一次擁有一整套可供比較的答案的時刻。只有達到標註者上限的條目才會進入時間線,而且上限必須是兩名或更多(例如 num_annotators_per_item: 2)。全項目一致性表使用的是同一批條目。因此,每個視窗包含的是基線背後那批條目中的一部分。

編碼者完成某個條目的時刻,是該方案答案的最後一次記錄在案的修改。條目沒有任何修改記錄時,Potato 依次退而使用編碼者離開該條目的時間,再退而使用編碼者開啟該條目的時間。開啟時間排在最後,因為一名先瀏覽完佇列、稍後再作答的編碼者,開啟每個條目的時間遠早於作答時間。完全沒有時間戳的條目不進入時間線,該部分會報告這類條目的數量。從其他工具匯入的標註是最常見的情況。

條目按這個時刻排序,再用以下兩種方式之一切分成視窗:

  • 等數量(window_by: count,預設)。每個視窗包含相同數量的條目。視窗數不超過條目數。因此,一個只有五個條目的試點不會產生空視窗。
  • 等時長(window_by: time)。每個視窗覆蓋相同長度的時鐘時間。編碼集中在幾段時間進行時,例如相隔一個月的兩個週末,兩段編碼之間的視窗就是空的。空視窗根本沒有一致性數值。在一致性頁面的表格中,空視窗看起來會像一致性驟降,而實際上那段時間沒有人編碼,等數量因此被設為預設方式。

每個視窗報告哪個係數

Potato 用每個視窗自己的條目重新執行全項目的一致性計算。因此,對於同一個方案,每個視窗和基線使用同一個係數。Potato 為每個方案選擇一個主係數,並優先使用經機遇校正的指標。百分比一致率僅因類別不平衡就會上升,即使編碼者的一致程度低於隨機水平,它也可能呈上升趨勢。係數取決於方案類型:

方案類型時間線上的係數
radio、select(每段摘錄一個程式碼)Krippendorff's α,名義尺度
likertKrippendorff's α,順序尺度
slider、numberKrippendorff's α,等距尺度
multiselect、hierarchical_multiselect(每段摘錄多個程式碼)使用 MASI 距離的 Krippendorff's α
span(已編碼的段落)位置 α;位置 α 無定義時改用詞元級 κ
multirate 及其他網格類方案對所有行合併計算的 α
沒有 α 的方案依次取 Fleiss' κ、Cohen's κ、加權 κ、相關係數或 ICC、片段 F1 和百分比一致率中第一個可用的指標

Krippendorff's α 在完全一致時為 1,在一致程度等於隨機水平時為 0。textbox 等自由文本方案沒有一致性指標,在時間線上沒有對應的行。當某個視窗的資料無法算出基線所用的係數時,該單元格不顯示數值,而不是改用另一種指標。兩種不同指標之間的下降沒有意義。

時間線單元格與單元格註記

每個方案佔一行。行首是作為基線的全項目係數,後面每個視窗一個單元格(W1、W2 等),顯示該視窗的係數和條目數。沒有數值的單元格會顯示一條簡短的註記,Potato 在時間線表格下方解釋每條註記。條目太少的視窗仍顯示數值,並附加一個標記。各條註記和該標記的含義如下:

註記含義
total agreement在該視窗的每個條目上,所有編碼者都選擇了同一個程式碼。經機遇校正的係數沒有可校正的分歧,因而無定義。這條註記標示的是一致性最好的情況。
undefined對於該視窗的資料,係數無定義,最常見的原因是所有判斷都落在同一個程式碼上。
no overlap在該視窗的條目上重疊的編碼者少於兩名。
no items沒有條目落入該視窗(僅限等時長視窗)。
too few to judge該視窗少於五個條目。數值照常顯示,但再校準提示會忽略該視窗。

如果項目使用 QDA 模式碼本,表格下方會有一行列出碼本修訂版本(r1 · r2 · r3)。碼本每發生一次變更,Potato 就把修訂號加一。新建、重新命名、更改顏色、移動或刪除一個程式碼,都各算一次變更。自 v2.9.0 起記錄的修訂版本帶有精確時間。更早的修訂版本按帶有該修訂號的最早一條標註確定日期。這個日期是一個下界,該修訂版本會被標為 approximate。HTML 頁面按編號列出修訂版本,下文的 JSON 報告則給出每個修訂版本的時間。指令碼可以把每次碼本編輯與視窗邊界對照起來,看某次指南修改是否改變了一致性。

配置

時間線不需要任何配置。任何每個條目有兩名或更多編碼者並啟用了一致性報告的項目,都會在 /admin/iaa 上看到這一部分。管理後臺把該頁面作為完整的一致性報告連結出來。要修改預設值,在現有配置中加入一個 calibration 程式碼塊:

yaml
calibration:
  enabled: true
  windows: 6
  window_by: count
  drop_threshold: 0.15

calibration 只接受以下四個鍵:

鍵類型預設值作用
enabledbooleantrue每次載入 /admin/iaa 時計算時間線。只有 false 會關閉這一部分。
windowsinteger6視窗數。六個視窗既能顯示趨勢,又能讓每個視窗有足夠的條目來計算經機遇校正的係數。在等數量模式下,視窗數不超過條目數。
window_bystringcountcount 表示等大小視窗,time 表示等時長視窗。其他任何值都按 count 處理。
drop_thresholdnumber0.15觸發再校準提示的、相對基線的下降比例。0.15 表示比全項目係數低 15%。

每次載入 /admin/iaa,時間線都要為每個視窗多做一次一致性計算。在大型項目上,設定 enabled: false 可以省去這部分開銷。此時時間線會同時從 /admin/iaa 和 /admin/iaa/drift JSON 報告中消失。

再校準輪次會重新執行培訓階段。因此,計劃進行再校準輪次的項目需要啟用 training,並在 phases 中有一個 training 條目。下面的配置是一項完整的雙編碼者研究,對開放式調查回答進行編碼,每個回答一個程式碼:

yaml
annotation_task_name: Open-ended responses, two coders
task_dir: .
output_annotation_dir: annotation_output/
data_files: [data/responses.json]
item_properties: {id_key: id, text_key: text}
 
annotation_schemes:
  - annotation_type: radio
    name: barrier
    description: Which barrier to care does the respondent describe?
    labels: [Cost, Distance, Wait time, Trust, None]
 
num_annotators_per_item: 2
 
training:
  enabled: true
  data_file: data/training.json
  allow_retry: true
  failure_action: repeat_training
 
phases:
  order: [training, annotation]
  training: {type: training}
  annotation: {type: annotation}
 
agreement_metrics: {enabled: true}
 
calibration:
  windows: 6
  window_by: count
  drop_threshold: 0.15

num_annotators_per_item: 2 讓每段摘錄都交給兩名編碼者。每段摘錄有兩名編碼者,每個窗口才有一致性數值。failure_action: repeat_training 讓未通過再校準輪次的編碼者重新做培訓條目,而不是結束該編碼者的參與。培訓檔案包含帶有商定程式碼和解釋的摘錄,格式見培訓階段頁面。

再校準提示

Potato 把每個方案的最近一個視窗與基線比較,當相對下降達到 drop_threshold 時給出提示。相對下降為 (基線 − 最近視窗) / 基線。基線取全項目係數而不是第一個視窗的係數,因為剛完成培訓的團隊在第一個視窗中一致性最不穩定。否則,一個異常好的第一個視窗會為整個研究定下標準。若基線 α 為 0.720,最近一個視窗為 0.580,下降為 19%,該部分會顯示:

text
Re-calibration suggested — barrier 19% below the project baseline (alpha_nominal 0.580 vs 0.720).

這條提示是給團隊負責人的建議。提示不會通知編碼者,也不會啟動再校準輪次。以下三種情況下,Potato 不會給出提示:

  • 更早的下降。 Potato 只判斷最近一個包含五個或更多條目的視窗。如果針對團隊已經恢復過來的下降發出提示,團隊會學會忽略提示。
  • 最近一個視窗無定義。 當最近一個視窗顯示 total agreement 或 undefined 時,Potato 不會退回去使用更早的視窗。
  • 基線等於或低於零。 一致性已處於隨機水平是全項目表格會報告的問題,而從零開始的百分比下降沒有意義。

通過管理 API 啟動校準輪次

一輪再校準會重置每名指定編碼者的培訓進度,並讓該編碼者回到培訓階段。編碼者再做一遍同樣的培訓條目。Potato 用同樣的正確答案為回答評分,並像第一遍那樣為每個錯誤答案顯示解釋。通過之後,編碼者進入 phases.order 中培訓之後的階段,並從上次停下的地方繼續。再校準輪次既不改變分配,也不改變已儲存的標註。Potato 不會向編碼者顯示任何表明再校準輪次已開始的訊息。啟動之前請先告知團隊。

再校準輪次通過管理 API、使用管理員 API 金鑰啟動。管理頁面上沒有啟動再校準輪次的按鈕。管理後臺頁面說明了金鑰從哪裡獲得。檢視哪些編碼者符合條件、上一輪結果如何:

bash
curl -H "X-API-Key: $KEY" http://localhost:8000/admin/calibration

響應列出可被召回的編碼者、以往的輪次,以及每名被召回編碼者在最近一輪中的進度。進度是 passed、failed、in_progress 或 unknown 之一,並附有已答、總數和答對的計數。處於標註階段、研究後階段或完成階段的編碼者符合條件。為所有符合條件的編碼者啟動一輪:

bash
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
     -d '{"reason": "barrier alpha fell 19%"}' \
     http://localhost:8000/admin/calibration/start

該呼叫返回輪次的 ID、被召回的編碼者,以及被跳過的編碼者及其原因。傳入 "usernames": ["coder1", "coder2"] 可以只召回指定的編碼者。省略 usernames 則召回所有符合條件的編碼者。指南漂移影響整個團隊。因此,召回所有人通常是正確的選擇。

仍停留在知情同意頁或說明頁的編碼者會列在響應的 skipped 下。未啟用 training 時,該呼叫返回 HTTP 400,不召回任何人。沒有培訓條目,被召回的編碼者會直接通過一個空的培訓階段。

在第一輪再校準之前規劃好培訓設定,原因有兩個。第一,未通過再校準輪次的編碼者由 training.failure_action 處理。在預設的 move_to_done 下,未通過再校準輪次會結束該編碼者在研究中的參與。未通過第一遍培訓也是同樣的結果。設定 failure_action: repeat_training 可以改為讓編碼者重新做培訓條目。第二,再校準輪次按 ID 選取培訓條目,向每名編碼者展示該編碼者第一次看到的條目。編碼者完成第一遍培訓之後才加入檔案的培訓條目,不會在再校準輪次中出現在該編碼者面前。請在編碼開始前把疑難案例放進培訓檔案。

團隊在哪裡討論分歧

再校準輪次重新執行培訓條目,因為這些條目有可供評分的已知答案。研究本身存在分歧的條目沒有標準答案。因此,Potato 不會把這些條目放進再校準輪次。再校準中的討論環節在 Potato 的其他地方進行。多人協作房間中的碰頭會房間(huddle)會帶領團隊逐一檢視團隊當前存在分歧的條目,並顯示每名編碼者最初給出的程式碼。在裁定佇列中,裁定者逐條解決有爭議的條目。質性研究團隊通常以修訂碼本中的程式碼定義來結束這類討論,下一個修訂版本隨後會出現在時間線上、位於之後各視窗的旁邊。

漂移報告與輪次日誌

漂移報告和輪次日誌獨立於標註匯出。沒有任何 python -m potato.export 格式包含漂移報告或輪次日誌。以 JSON 格式獲取時間線:

bash
curl -H "X-API-Key: $KEY" http://localhost:8000/admin/iaa/drift

JSON 報告包含以下欄位:

  • windows 列出每個視窗的序號、起止時間、條目數、sparse 標誌、條目 ID,以及限定在該視窗內的完整一致性報告。
  • schemas 按方案給出主指標、基線,以及每個視窗一個數據點,包含該視窗的數值、註記和條目數。
  • triggers 列出每個觸發了提示的方案,附帶基線、最近值和相對下降。
  • markers 列出碼本修訂版本,附帶每個修訂版本的時間,以及標示近似日期的 inferred 標誌。
  • n_items 和 n_untimed_items 統計時間線上和時間線外的條目數,reason 說明報告為空的原因。

時間均為以秒為單位的 Unix 時間戳。沒有可比較的內容時報告為空,例如沒有任何條目達到標註者上限,或所有帶時間戳的條目都落在同一個視窗中。此時 reason 欄位會說明原因。

Potato 把每一輪記錄在 <task_dir>/project.sqlite 的 calibration_rounds 表中,包括該輪的開始時間、啟動該輪的管理員(通過 API 金鑰呼叫時為 admin)、原因文本,以及被召回的編碼者。輪次日誌和分視窗的係數為方法部分提供每次再校準的日期,以及每輪前後的一致性。質性研究的審計軌跡需要這兩份記錄。編碼者的培訓答案儲存在 user_state.json 中,每一輪再校準都會重置這些答案。要保留第一遍培訓的得分,請在每輪開始前儲存一份標註輸出目錄的副本。

延伸閱讀

實現細節請參閱源文件。

參考文獻

  • Hennessy, M., Bleakley, A., & Ellithorpe, M. E. (2022). Evaluating and tracking qualitative content coder performance using item response theory. Quality & Quantity, 57(2), 1231-1245. https://doi.org/10.1007/s11135-022-01397-7
  • Lacy, S., Watson, B. R., Riffe, D., & Lovejoy, J. (2015). Issues and best practices in content analysis. Journalism & Mass Communication Quarterly, 92(4), 791-811. https://doi.org/10.1177/1077699015607338(轉引自 Hennessy et al., 2022)