본문으로 건너뛰기
튜토리얼29분 분량

두 코더로 인터뷰 전사문을 코딩하고 알파 보고하기

Potato에서 두 코더가 하나의 코드북을 인터뷰 발췌문에 적용하고, 코드별 Krippendorff의 알파를 보고하고, 불일치를 해소하고, QDPX 프로젝트를 내보냅니다.

Potato Team

인터뷰를 팀으로 코딩하는 정성 연구자와 혼합 방법 연구자는 이 튜토리얼을 따라 Potato 2.13.1에서 두 코더가 공개 라이선스 인터뷰 전사문 여섯 편을 코딩하게 하고, 방법 절에 Krippendorff의 알파를 보고하고, 불일치를 해소하고, 코딩된 프로젝트를 NVivo, ATLAS.ti, MAXQDA로 작업하는 동료에게 넘길 수 있습니다. 이 튜토리얼은 코드북이 이미 있다고 가정합니다. Potato의 QDA 모드는 한 명의 분석가가 인터뷰를 읽으며 코드북을 키워 가는 앞 단계에 알맞고, QDA 모드 게시물이 그 단계를 안내합니다. 정성 데이터 분석 소프트웨어 비교는 도구별 가격과 기능을 다루며, Potato의 정성 연구는 Potato의 정성 기능을 한곳에 나열합니다.

인터뷰

전사문은 Mário Rosado de Souza, Robert Haines, Markel Vigo, Caroline Jay가 Zenodo에 등록한 What makes research software sustainable? Anonymized interview transcripts에서 가져왔습니다(참고문헌 2). 이 데이터에는 연구용 소프트웨어 개발자와의 인터뷰 19편이 인터뷰당 PDF 하나로 CC BY-SA 4.0 라이선스 아래 있습니다. 이 인터뷰의 바탕이 된 연구는 CHASE 2019에 실렸습니다(참고문헌 1). 아래의 발췌문 파일처럼 전사문에서 파생해 공유하는 파일은 같은 라이선스를 따르며 네 저자를 명시해야 합니다. 이 튜토리얼은 처음 여섯 편의 인터뷰를 사용합니다. 여섯 편 모두에서 인터뷰어는 지속 가능한 소프트웨어가 무엇인지, 어떤 특징이 소프트웨어를 지속 가능하게 만드는지, 소프트웨어가 유지되지 않으면 어떻게 되는지를 묻습니다. Zenodo 레코드에서 Interview01.pdf부터 Interview06.pdf까지 내려받으세요.

신뢰도에는 고정된 단위가 필요하며, 두 코더가 같은 텍스트 조각에 대해 같은 질문에 답해야 합니다. 여기서 단위는 참여자의 답변 하나입니다. 아래 스크립트는 pdftotext(Poppler의 도구)가 각 PDF를 텍스트로 바꾼 뒤 전사문을 읽어, 20단어 이상인 참여자의 답변을 모두 남기고 각 답변 옆에 인터뷰어의 마지막 질문을 기록합니다.

python
"""Split interview transcripts into one excerpt per participant answer.
 
Usage: python prepare_excerpts.py transcripts/*.txt > data/excerpts.jsonl
"""
import json
import re
import sys
from pathlib import Path
 
TURN = re.compile(r"^\s*(I\d*|P\d*)\s*[-:]\s*(.*)$", re.IGNORECASE)
MIN_WORDS = 20  # shorter answers ("Yeah", "Right") are not coded
 
for path in sys.argv[1:]:
    interview = Path(path).stem.replace("Interview", "I").replace("interview", "I")
    turns, speaker, words = [], None, []
    for line in Path(path).read_text(encoding="utf-8").splitlines():
        line = re.sub(r"!\s*$", "", line).strip()  # the PDFs end some lines with "!"
        match = TURN.match(line)
        if match:
            if speaker:
                turns.append((speaker, " ".join(words)))
            speaker, words = match.group(1).upper()[0], [match.group(2)]
        elif line and speaker:
            words.append(line)
    if speaker:
        turns.append((speaker, " ".join(words)))
 
    question, n = "", 0
    for speaker, text in turns:
        text = re.sub(r"\s+", " ", text).strip()
        if speaker == "I":
            if "?" in text:  # keep the last question, skipping "Mm" and "I see"
                question = text
        elif len(text.split()) >= MIN_WORDS:
            n += 1
            print(json.dumps({"id": f"{interview}-{n:02d}", "interview": interview,
                              "question": question, "text": text}, ensure_ascii=False))

Potato를 설치하고 여섯 편의 전사문에 스크립트를 실행합니다.

bash
pip install potato-annotation==2.13.1
mkdir -p transcripts data
for f in Interview0[1-6].pdf; do pdftotext -layout "$f" "transcripts/${f%.pdf}.txt"; done
python prepare_excerpts.py transcripts/*.txt > data/excerpts.jsonl

여섯 편의 인터뷰에서 발췌문 52개가 나오며, 가장 짧은 인터뷰는 5개, 가장 긴 인터뷰는 15개입니다. data/excerpts.jsonl의 각 줄이 발췌문 하나이며, 여기서는 답변을 줄여 보여 줍니다.

json
{"id": "I01-07", "interview": "I01", "question": "Okay. Um, regarding the software you developed, was sustainability a consideration?", "text": "Sustainability most certainly was a consideration. ..."}

전사문은 화자를 I1:과 I1 -의 두 가지 방식으로 표기하며, 스크립트는 둘 다 읽습니다. 인터뷰 1은 인터뷰어의 첫 질문을 참여자의 발화로 표기하므로, 그 인터뷰의 처음 네 발췌문에는 답변 옆에 질문이 없습니다. 코딩을 시작하기 전에 각 인터뷰의 발췌문 몇 개를 PDF와 대조해 읽어 보세요.

코드북

코드북에는 열 개의 코드가 있으며, 여섯 편의 인터뷰를 읽은 뒤 작성했습니다. 아홉 개의 코드는 참여자가 제기하는 주제를 나타내고, 열 번째 코드인 "No code applies"는 모든 발췌문에 답을 줍니다. Potato의 신뢰도 내보내기는 코더가 아무것도 고르지 않은 발췌문을 제외합니다. 열 번째 코드가 없으면, 한 코더는 주제를 보았고 다른 코더는 보지 못한 발췌문이 불일치로 계산되지 않고 알파에서 빠져 버립니다. 각 코드의 정의는 코드의 tooltip이며, 코더는 코드 위에 마우스를 올려 정의를 봅니다.

하나의 답변이 두 주제를 제기하는 경우가 많으므로 multiselect 질문이 코드북을 기록합니다. Potato는 코드북을 CSV 파일에서 hierarchical_multiselect 질문으로 불러올 수도 있으며(내용 분석), 이 질문 유형은 코드가 백 개인 중첩 코드북에 알맞습니다. 2.13.1에서 계층형 질문 유형에는 이 튜토리얼의 워크플로에 한 가지 공백이 있습니다. 판정 페이지에서 판정자는 한 코더의 답변을 채택할 수 있지만 두 답변을 결합할 수는 없습니다. 2.12.1에서는 codebook과 qdpx 내보내기도 이 질문의 코드를 빠뜨렸습니다.

설정

아래 설정은 완전하며 2.12.1과 2.13.1에서 python -m potato.validate_cli config.yaml --strict를 통과합니다.

yaml
annotation_task_name: Research software sustainability interviews
task_dir: .
output_annotation_dir: annotation_output/
data_files:
  - data/excerpts.jsonl
item_properties:
  id_key: id
  text_key: text
 
user_config:
  allow_all_users: true
  users: []
 
# Both coders code every excerpt independently
num_annotators_per_item: 2
 
instance_display:
  fields:
    - {key: question, type: text, label: Interviewer}
    - {key: text, type: text, label: Participant, span_target: true}
 
annotation_schemes:
  - annotation_type: multiselect
    name: codes
    description: Which codes apply to this answer? Hover over a code for its definition.
    humanize_labels: false
    labels:
      - {name: Documentation, tooltip: "Manuals, API descriptions, examples, or software that explains itself"}
      - {name: Testing, tooltip: "Automated tests, or the effort and limits of writing them"}
      - {name: Code design, tooltip: "Modular, generic, narrowly scoped, or well-commented code"}
      - {name: Reuse of libraries, tooltip: "Building on maintained libraries instead of bespoke code"}
      - {name: Public source code, tooltip: "Version control, GitHub, or another place where anyone can find the code"}
      - {name: User community, tooltip: "People or organizations who use the software, rely on it, or answer questions about it"}
      - {name: More than one maintainer, tooltip: "Someone other than the original developer can build, maintain, or take over the software"}
      - {name: Funding, tooltip: "Grants, budgets, or money to keep the software maintained, or the lack of them"}
      - {name: Software decay, tooltip: "Software stops working as platforms, libraries, or servers change, or is abandoned"}
      - {name: No code applies, tooltip: "The answer touches none of the codes above"}
  - annotation_type: span
    name: quotes
    description: Highlight the words that show each code you ticked.
    target_field: text
    humanize_labels: false
    labels: [Documentation, Testing, Code design, Reuse of libraries, Public source code, User community, More than one maintainer, Funding, Software decay]
 
adjudication:
  enabled: true
  adjudicator_users: [lead]
  min_annotations: 2

num_annotators_per_item: 2는 모든 발췌문을 두 코더에게 보내며, Potato는 어느 코더에게도 상대의 코드를 보여 주지 않습니다. instance_display는 인터뷰어의 질문을 답변 위에 두고, span_target: true는 코더가 답변에서만 강조할 수 있게 합니다. quotes 질문은 각 코드의 근거가 되는 단어를 글쓰기용으로 수집합니다. Potato는 체크한 코드로 신뢰도를 계산하며 강조 표시는 무시합니다. humanize_labels: false가 없으면 Potato는 코드의 모든 단어를 대문자로 시작하게 하여 "Reuse Of Libraries"로 표시합니다. adjudication 블록은 두 코더가 모두 코딩한 모든 발췌문에 대해 사용자 lead를 판정자로 지정합니다.

더 큰 말뭉치에서는 두 코더가 발췌문의 표본을 함께 코딩하고 나머지 발췌문을 두 코더에게 나누는 설계가 흔합니다. 위 설정의 num_annotators_per_item: 2를 다음 줄로 바꾸면 두 코더가 각 인터뷰 안에서 뽑은 30% 표본을 코딩합니다.

yaml
num_annotators_per_item:
  default: 1
  overlap_sample:
    fraction: 0.3
    count: 2
    stratify_by: interview
    seed: 11
assignment_strategy: random

코더가 두 명이면 assignment_strategy: random을 유지하세요. Potato의 기본 fixed_order 할당에서는 이 표본과 코더 두 명으로 한 테스트에서 52개의 발췌문이 모두 첫 번째 코더에게 할당되었습니다. 그러면 두 번째 코더는 첫 번째 코더가 아직 코딩하지 않은 표본 밖의 발췌문 26개를 받았고, 그 26개의 발췌문이 두 번 코딩되었습니다. 무작위 할당에서는 두 코더가 각각 34개의 발췌문을 코딩했으며, 이는 15개 발췌문의 표본과 나머지 37개 발췌문이 필요로 하는 수보다 합계로 하나 많습니다. 이 수치는 Potato 2.12.1에서 나온 것입니다. Potato 2.13.1은 assignment_hold_minutes를 추가하며, 일이 떨어진 코더에게 다른 코더가 아직 닿지 못한 발췌문을 공유하는 대신 넘겨줍니다(작업 할당).

발췌문 코딩

프로젝트 폴더에서 서버를 시작합니다.

bash
potato start config.yaml -p 8000

각 코더는 http://localhost:8000을 열고 사용자 이름과 비밀번호로 등록한 뒤 첫 번째 발췌문에서 시작합니다. 다른 컴퓨터의 코더에게는 그 컴퓨터가 닿을 수 있는 주소의 서버가 필요하며, VPS에 Potato 배포하기가 이를 설명합니다. 각 발췌문에서 코더는 해당하는 모든 코드를 체크합니다. 그런 다음 "Highlight the words that show each code you ticked" 아래에서 코드를 클릭하고 답변의 단어 위로 끌어 선택합니다. 강조는 끌어서 지나간 글자만 정확히 덮으며 단어 경계에 맞춰지지 않습니다. 다음을 클릭하면 발췌문이 저장됩니다.

이 페이지의 바탕이 된 테스트 실행

이 페이지의 수치는 실행 중인 Potato 2.12.1 서버에서 스크립트로 작동하는 두 코더가 작업한 결과에서 나왔으며, 각 코더는 어노테이션 페이지가 보내는 것과 같은 요청으로 모든 발췌문을 저장했습니다. 이후 내보내기와 일치도 보고서는 저장된 코딩에 대해 Potato 2.13.1로 다시 실행했습니다. 첫 번째 코더의 코드는 각 답변을 꼼꼼히 읽고 코드당 강조 구절 하나로 정했습니다. 두 번째 코더의 코드는 독립적으로 작성되어 불확실한 답변에서 달라지며, 두 번째 코더는 문장 전체를 강조했습니다. 따라서 알파 값은 모의 코더 두 명을 나타낼 뿐 실제 코더가 이 코드북을 쓸 때의 신뢰도에 대해서는 아무것도 말해 주지 않습니다. 브라우저에서 확인한 결과, 손으로 그은 강조는 스크립트가 쓴 것과 같은 답변 텍스트에 대한 오프셋으로 저장되었습니다.

신뢰도 내보내기의 Krippendorff 알파

두 코더가 모두 끝나면 신뢰도 내보내기를 실행합니다.

bash
python -m potato.export --config config.yaml --format reliability --output export/

이 명령은 export/reliability.csv와 export/reliability.md를 씁니다. Markdown 파일은 방법 절에 붙여 넣을 표입니다.

text
| Variable | Level | Krippendorff's α | 95% CI | % agreement | Units | Coders |
|---|---|---|---|---|---|---|
| codes | masi | 0.677 | [0.58, 0.764] | 53.846 | 52 | 2 |
| quotes | positional | 0.284 | [0.225, 0.346] | 75.404 | 46 | 2 |
 
Intervals: percentile bootstrap over units, 1000 resamples.

표에는 질문당 한 행이 있습니다. quotes 행은 Potato 2.13.1에서 새로 생겼으며, 이 행은 아래의 강조된 구절에 관한 절에서 설명합니다. Potato 2.12.1은 스팬 질문을 표에서 제외했습니다. Potato는 각 발췌문에 대해 각 코더가 고른 코드 집합에 MASI 거리를 써서 Krippendorff의 알파를 계산합니다(참고문헌 3). 두 집합이 겹치면 MASI는 부분 점수를 줍니다. {Funding, User community}와 {Funding}을 고른 두 코더는 공통 코드가 하나도 없는 두 코더보다 더 많은 점수를 받습니다. 구간은 고정된 시드로 발췌문을 1,000번 재표집하는 백분위 부트스트랩입니다. 퍼센트 일치도 53.846은 두 코더가 같은 코드 집합을 골랐을 때에만 발췌문을 일치로 세며, 52개의 발췌문 중 28개가 이 기준을 충족했습니다.

방법 절은 결과를 "두 코더가 52개의 발췌문을 모두 독립적으로 코딩했다. 발췌문별 코드 집합에 MASI 거리를 쓴 Krippendorff의 알파는 0.677(95% 부트스트랩 구간 0.58~0.764)이었다."와 같은 한 문장으로 보고할 수 있습니다. 내용 분석의 관례적 기준은 변수를 신뢰하려면 0.800, 잠정적 결론에는 0.667이며, 어노테이터 간 일치도가 두 기준을 읽는 방법을 설명합니다.

관리자 대시보드는 코딩이 진행되는 동안 같은 계수를 보여 줍니다. http://localhost:8000/admin/iaa를 열고 Potato가 프로젝트 폴더의 admin_api_key.txt에 쓴 관리자 키를 입력하세요. 테스트 실행에서 이 페이지는 alpha_masi 0.677과 평균 Jaccard 0.788을 보고했습니다. Potato 2.13.1은 0.6에서 0.8 사이의 값에 "substantial", 0.8을 넘는 값에 "strong"이라는 라벨을 붙이며, Potato 2.12.1은 0.6 이상의 모든 값을 "strong agreement"라고 불렀습니다. 위의 내용 분석 기준은 더 높은 문턱을 둡니다.

코드별 알파

많은 정성 연구의 방법 절은 각 발췌문에서 각 코드를 있음 또는 없음으로 채점하여 코드별 신뢰도를 보고합니다. Potato 2.13.1은 코드별 알파를 보고하지 않으므로, CSV 내보내기에서 직접 계산하세요. 아래 스크립트는 신뢰도 내보내기가 쓰는 것과 같은 알파 함수를 명목 수준으로 호출합니다.

python
"""Krippendorff's alpha for each code, scored as present or absent per excerpt.
 
Usage: python alpha_by_code.py export/annotations.csv
"""
import csv
import sys
from collections import defaultdict
 
from potato.server_utils.iaa.alpha import krippendorff_alpha
 
chosen = defaultdict(dict)  # excerpt -> coder -> set of codes
for row in csv.DictReader(open(sys.argv[1], encoding="utf-8")):
    chosen[row["instance_id"]][row["user_id"]] = {
        col[len("codes."):] for col, value in row.items()
        if col.startswith("codes.") and value}
both = {unit: by for unit, by in chosen.items() if len(by) == 2}
codes = sorted(set().union(*(c for by in both.values() for c in by.values())))
 
print("code,alpha,either_coder,both_coders")
for code in codes:
    rows = [(coder, unit, int(code in c)) for unit, by in both.items() for coder, c in by.items()]
    either = sum(any(code in c for c in by.values()) for by in both.values())
    agreed = sum(all(code in c for c in by.values()) for by in both.values())
    print(f"{code},{krippendorff_alpha(rows, level='nominal'):.3f},{either},{agreed}")

CSV를 내보내고 스크립트를 실행합니다.

bash
python -m potato.export --config config.yaml --format csv --output export/
python alpha_by_code.py export/annotations.csv

테스트 실행은 다음 값을 냈으며, 여기서는 알파 순으로 정렬했습니다.

코드알파어느 한 코더가 코드를 부여한 발췌문두 코더 모두
Testing1.00066
Funding0.9451211
Documentation0.91376
No code applies0.91376
Reuse of libraries0.88054
Code design0.85497
Software decay0.772139
User community0.7521611
More than one maintainer0.681127
Public source code0.56594

"Public source code"는 0.667 아래로 떨어지는데, 한 코더가 참여자가 GitHub을 언급할 때마다 이 코드를 적용했기 때문입니다. "More than one maintainer"와 "User community"는 둘 다 0.800 아래이며, 참여자가 다른 사람들이 소프트웨어를 살려 두는 방식을 설명할 때마다 두 코드가 겹칩니다. "Reuse of libraries"처럼 발췌문 다섯 개에 적용된 코드는 불일치 하나에도 크게 움직이므로, 코드별 값은 두 개의 개수 열과 함께 읽으세요.

강조된 구절의 일치도

스팬 질문에 대해 Potato 2.13.1의 관리자 페이지는 토큰 수준 카파, 정확 일치와 부분 일치의 스팬 F1, positional_alpha라는 글자 수준 알파, Mathet의 감마를 보고합니다. 어느 한 코더가 강조한 46개의 발췌문에서 이 페이지는 토큰 수준 카파 0.296, 정확 스팬 F1 0, 부분 스팬 F1 0.837, positional_alpha 0.183, 감마 0.575를 보고했습니다. 한 코더의 강조 중 어느 것도 다른 코더의 강조와 같은 글자에서 시작하고 끝나지 않으므로 정확 F1은 0입니다. 신뢰도 내보내기의 quotes 행은 0.284인데, 내보내기는 모든 발췌문의 글자를 하나의 알파로 합치지만 관리자 페이지는 발췌문에 걸쳐 알파를 평균하기 때문입니다. 2.12.1에서는 조회 오류 때문에 스팬 행이 항목 0개로 n/a로 표시되었습니다. 이 사이트의 스팬 일치도 계산기는 다른 일치 규칙으로 스팬 F1을, 그리고 글자 수준 알파를 브라우저에서 계산합니다. 계산기는 강조당 한 행으로 항목, 어노테이터, 라벨, 시작, 끝을 받으며, 인용 보고서에 이 필드가 모두 있습니다.

bash
python -m potato.export --config config.yaml --format quotation_report --output export/

이 명령은 강조당 한 행으로, 인용문, 시작 및 끝 오프셋, 발췌문, 코더를 담은 export/quotations.csv를 씁니다.

Potato 2.12.1에서 krippendorff_alpha_u라는 이름이었던 positional_alpha는 글자 수준 알파이며 Krippendorff의 단위화 알파가 아닙니다. Potato는 답변의 각 글자에 그 글자를 덮는 코드의 집합을 부여하고, 글자들에 명목 알파를 실행하고, 발췌문에 걸쳐 평균합니다. 정성 코더는 같은 단어에 코드를 두 개 주는 일이 흔한데, 2.13.1부터 코드가 두 개인 글자는 둘 중 하나만 있는 글자와 다른 값으로 계산됩니다. Potato 2.12.1은 공유된 글자에 대해 더 긴 강조의 코드만 남겼습니다. 스팬의 일치도가 스팬 측정을 설명합니다. 방법 절에는 발췌문 코드에 대한 알파를 보고하고 강조는 인용 근거로 다루세요.

불일치 해소

알파는 두 코더의 독립적 코딩을 설명합니다. 알파는 누군가 불일치를 해소하기 전의 코딩 그대로에서 보고하세요. 최종 코드를 만들기 위해 리드는 사용자 이름 lead로 등록한 뒤 http://localhost:8000/adjudicate를 엽니다. 대기열에는 두 코더가 서로 다른 코드 집합을 고른 모든 발췌문이 나열됩니다. 테스트 실행에서 대기열에는 24개의 발췌문이 있었습니다. 각 발췌문에서 페이지는 두 코더의 코드와 강조, 최종 집합을 기록할 코드별 체크박스, 확신 수준, 메모, Potato의 기본 목록에서 고르는 오류 범주를 보여 줍니다. 체크박스 하나는 그 발췌문을 코드북 변경 대상으로 표시합니다.

테스트 실행에서 리드는 불일치 11건을 코더 오류로, 10건을 코드북의 공백으로, 2건을 모호한 텍스트로, 1건을 주관적 의견 차이로 태그했습니다. 발췌문 두 개가 코드북 변경 대상으로 표시되었습니다. 한 표시는 "Public source code"를 공개 코드를 지속 가능성의 조건으로 꼽는 답변으로 좁힙니다. 다른 표시는 사용성 코드를 요청하는데, 참여자들이 배우고 실행하기 쉬운 소프트웨어를 이야기하지만 그 주제를 다루는 코드가 없기 때문입니다.

결정을 내보냅니다.

bash
python -m potato.export --config config.yaml --format adjudication --output export/

이 명령은 판정한 발췌문당 한 행인 export/adjudicated.csv와, 메모, 오류 범주, 코드북 표시를 담은 export/adjudication_log.jsonl을 씁니다. adjudicated.csv는 대기열의 24개 발췌문만 다룹니다. 세 번째 스크립트가 판정된 코드를 두 코더가 일치했던 코드와 합칩니다.

python
"""One final set of codes per excerpt: the adjudicated set where the coders
disagreed, and the coders' shared set everywhere else.
 
Usage: python final_codes.py export/annotations.csv export/adjudicated.csv > final_codes.csv
"""
import csv
import json
import sys
from collections import defaultdict
 
chosen = defaultdict(list)
for row in csv.DictReader(open(sys.argv[1], encoding="utf-8")):
    chosen[row["instance_id"]].append(
        {col[len("codes."):] for col, v in row.items() if col.startswith("codes.") and v})
resolved = {row["instance_id"]: set(json.loads(row["value"]))
            for row in csv.DictReader(open(sys.argv[2], encoding="utf-8"))
            if row["schema"] == "codes"}
 
out = csv.writer(sys.stdout)
out.writerow(["excerpt", "codes", "source"])
for excerpt, sets in sorted(chosen.items()):
    if excerpt in resolved:
        out.writerow([excerpt, "; ".join(sorted(resolved[excerpt])), "adjudicated"])
    elif all(s == sets[0] for s in sets):
        out.writerow([excerpt, "; ".join(sorted(sets[0])), "agreed"])
    else:
        out.writerow([excerpt, "", "NOT RESOLVED"])

테스트 실행에서 final_codes.csv는 52행이었고, 28개가 일치, 24개가 판정이었습니다. 코드북이 바뀐 뒤에는 첫 라운드의 알파가 더 이상 팀이 쓰는 코드북을 설명하지 않습니다. 두 코더가 개정된 코드북으로 새 발췌문 집합을 코딩하게 하고 그 라운드의 알파를 보고하세요. 판정과 불일치 해소가 판정 설계를 더 자세히 다룹니다.

REFI-QDA 프로젝트 파일 내보내기

REFI-QDA는 NVivo, ATLAS.ti, MAXQDA, QualCoder가 읽는 교환 표준이며, .qdpx 파일에는 프로젝트의 텍스트, 코드, 코딩이 들어 있습니다. 코딩된 프로젝트를 내보냅니다.

bash
python -m potato.export --config config.yaml --format qdpx --output export/

이 명령은 export/Research_software_sustainability_interviews.qdpx를 씁니다. 테스트 실행에서 이 파일에는 다음이 들어 있었습니다.

  • 발췌문당 하나씩 텍스트 소스 52개
  • 정의가 붙은 열 개의 코드
  • 사용자로서의 두 코더
  • 강조 154개, 각각 그것을 만든 코더와 함께
  • 발췌문 전체에 적용된 코드 167개

이 파일에는 두 코더의 코딩이 모두 들어 있으며 판정된 코드는 파일에 없습니다.

Potato 2.13.1부터 파일은 REFI-QDA 프로젝트 스키마에 대해 검증을 통과합니다. 2.12.1에서는 프로젝트에 강조와 발췌문 전체 코드가 모두 있으면 파일이 스키마 검사에 실패했는데, Potato가 각 코더의 강조와 코드를 차례로 썼기 때문이며, 스크립트로 각 소스의 요소를 재정렬해야 했습니다.

파일의 모든 강조와 발췌문 전체 코드는 그것을 만든 코더를 명시합니다. 2.12.1에서는 발췌문 전체 코드가 코더를 명시하지 않았습니다. 프로젝트 가져오기는 potato import가 .qdpx 파일을 읽는 방식을 다룹니다. 파일을 potato import -i Research_software_sustainability_interviews.qdpx -o reimport로 Potato 2.13.1에 다시 가져오면 텍스트 52개와 모든 강조 154개가 같은 오프셋으로 나오며, 다음 손실이 있습니다.

  • 강조는 모든 코더에게 제안으로 도착합니다. 각 강조는 코더의 이름을 annotator 필드에 유지하며, Potato 2.12.1은 이를 버렸습니다.
  • 발췌문 전체 코드는 각 항목의 document_codes 필드로 도착하며, 이 필드를 읽는 질문은 없습니다.
  • 내보내기가 답변 텍스트만 쓰므로 인터뷰어의 질문과 인터뷰 번호는 남지 않습니다.
  • 코드 정의는 각 스팬 라벨의 description으로 도착하며, 스팬 질문은 description을 표시하지 않습니다.

팀 코딩을 위한 다른 도구

NVivo의 코딩 비교 쿼리는 두 사용자 또는 사용자 그룹 사이에서 각 파일의 각 코드에 대해 Cohen의 카파와 퍼센트 일치도를 보고합니다. NVivo는 일치를 텍스트의 글자 수로 셉니다. ATLAS.ti의 코더 간 일치도 도구는 코더들의 프로젝트를 병합한 뒤 퍼센트 일치도, Holsti 지수, Krippendorff 알파 계열을 보고하며, ATLAS.ti 매뉴얼은 Cohen의 카파를 의도적으로 뺐다고 말합니다. MAXQDA는 문서 수준에서 퍼센트 일치도와 우연 보정 카파를, 세그먼트 수준에서 Brennan과 Prediger의 카파를 보고합니다. 세그먼트 수준에서는 코딩이 기본적으로 90% 이상 겹칠 때 두 코딩이 일치합니다. Dedoose의 Testing Center는 코더의 코드 적용을 전문가의 것과 Cohen의 카파로 비교합니다. QualCoder는 무료 데스크톱 프로그램이며 코더를 Cohen의 카파로 비교합니다. 이 도구들은 모두 텍스트뿐 아니라 오디오, 비디오, PDF도 코딩하며, 각각 그 도구로 이미 작업하는 팀에 알맞습니다.

Potato는 팀이 통제하는 서버의 무료 도구에서 구간이 있는 알파를 원하고, 데스크톱 설치 없이 브라우저에서 코딩하는 팀에 알맞습니다. 정성 데이터 분석 소프트웨어 비교는 각 도구의 가격, 호스팅, AI 기능을 나열합니다.

팀 코딩에서 Potato의 한계

  • 텍스트만. Potato는 텍스트를 코딩하며, REFI-QDA 가져오기는 텍스트 소스만 읽습니다. potato transcripts --transcribe --diarize가 녹음을 먼저 전사문으로 바꿉니다.
  • 내보내기에 코드별 알파 없음. reliability 내보내기는 질문당 한 행을 주며, 코드별 알파에는 위의 스크립트가 필요합니다.
  • .qdpx 파일에서 발췌문당 소스 하나. 발췌문 단위로 코딩한 프로젝트는 NVivo나 ATLAS.ti에서 인터뷰 여섯 편이 아니라 답변당 하나씩 소스 52개가 됩니다.
  • .qdpx 파일에는 두 코더의 원본 코딩. 판정된 코드는 adjudicated.csv로만 나갑니다.

다음으로 볼 자료

참고문헌

  1. Rosado de Souza, M., Haines, R., Vigo, M., & Jay, C. (2019). What Makes Research Software Sustainable? An Interview Study with Research Software Engineers. 2019 IEEE/ACM 12th International Workshop on Cooperative and Human Aspects of Software Engineering (CHASE), 135-138. https://doi.org/10.1109/CHASE.2019.00039
  2. de Souza, M. R., Haines, R., Vigo, M., & Jay, C. (2019). What makes research software sustainable? Anonymized interview transcripts [Data set]. Zenodo. https://doi.org/10.5281/zenodo.1345067
  3. Passonneau, R. (2006). Measuring Agreement on Set-valued Items (MASI) for Semantic and Pragmatic Annotation. Proceedings of the Fifth International Conference on Language Resources and Evaluation (LREC'06). https://aclanthology.org/L06-1392/