학습자는 생성형 AI를 사용해 과제를 더 빨리 완성할 수 있지만, 그 속도가 장기 역량으로 이어지는지는 자신이 어떤 인지적 작업을 남겨 두었는지에 달려 있다. 따라서 학습자는 AI를 사고와 판단의 대체물이 아니라 자기 역량을 증폭하는 augmentation 도구로 배치해야 한다.

이 문서의 핵심 흐름은 다음과 같다.

먼저 스스로 만들고, 판단만은 직접 하며, 마지막에는 AI 없이 다시 해본다.

1. 이 문서가 구분하는 것: 성과와 역량

AI 사용의 효과를 논의하려면 두 결과를 분리해야 한다.

  • 단기 성과(task performance): 지금 과제를 얼마나 빠르고 매끄럽게 완성했는가.
  • 장기 역량(skill formation): 도구 없이 원리를 설명하고, 새로운 문제에 적용하고, 오류를 수정할 수 있는가.

학습자가 AI를 이용해 첫 번째 결과를 높일 수는 있다. 그러나 두 번째 결과가 같은 속도로 따라오는지는 별도로 확인해야 한다. 두 결과가 갈리는 지점은 AI의 성능이 아니라, 학습자가 어떤 인지적 작업을 수행했는가다. 더 강하게 말하면 학습자가 AI에 작업을 넘겨도 단기 성과가 높아지지 않을 수 있고, 성과가 높아도 학습이 약해질 수 있다.

따라서 학습의 질문은 “AI가 결과물을 더 좋게 만들었는가?”에서 끝나면 안 된다.

AI가 사라진 뒤에도 학습자가 설명·판단·적용할 수 있는가?

2. 학습을 설명하는 이론: 누가 작업했고, 누가 자기 상태를 판단하는가

이 장의 이론들은 서로 다른 목록이 아니라 두 질문에 답한다. 첫째, 학습자가 무엇을 하기로 했고, 실제로 스스로 만들고 꺼내고 어려움을 통과하고 설명했는가. 둘째, 학습자가 자신의 상태를 정확히 판단하는가. 성취목표·생성 효과·인출 연습·바람직한 어려움·동료 튜터링은 첫 질문을, 인지적 외주화와 유창성 착각은 둘째 질문을 다룬다. 형성평가는 두 질문의 증거를 다음 행동으로 연결하는 배경 이론이며, 6장에서 평가 설계의 관점으로 다룬다.

2.1 성취목표이론: 어떤 작업을 성공으로 볼 것인가

성취목표이론은 학습자가 역량을 어떻게 정의하고 평가하는지를 설명한다(Dweck & Leggett, 1988).

  • 숙련목표(mastery goal): 과제를 이해하고 역량을 발전시키는 데 초점을 둔다.
  • 성과목표(performance goal): 자신의 능력을 보여 주거나 타인보다 좋은 결과를 내는 데 초점을 둔다.

후속 연구는 목표의 방향을 접근(approach)과 회피(avoidance)로 나누고, 성공의 기준을 과제(task), 자기(self), 타인(other)으로 구분했다. Elliot, Murayama & Pekrun(2011)의 3×2 모델은 바로 이 기준 × 방향 구조를 다룬다.

성과목표가 항상 나쁜 것은 아니다. 시험, 납품, 합격처럼 외부 성과가 필요한 상황에서는 성과-접근 목표가 기능할 수 있다. 문제는 “유능해 보이는 결과물”이 “실제로 이해한 결과물”을 대신할 때 생긴다.

AI 시대의 두 목표는 다음처럼 구분할 수 있다.

  • 성과목표: “AI를 활용해 좋은 결과물을 제출한다.”
  • 숙련목표: “AI가 만든 결과물을 설명하고, 검증하고, 변형할 수 있다.”

Noordzij, Giel & van Mierlo(2021)의 실험 메타분석은 유도된 숙련-접근 목표가 성과-접근 목표보다 과제 수행에 유리할 수 있음을 보고했다(d = 0.28). 이 이점은 특히 과제 기준으로 목표를 제시할 때 나타났고, 자기 기준에서는 뚜렷하지 않았다. 다만 효과는 과제와 맥락에 따라 달라진다.

프로토콜 연결: 이 이론은 5장 0단계에서 “이번 과제에 숙련목표가 걸려 있는가, 결과 제출만 필요한가”를 판단하게 한다. Bastani 외(2025)의 GPT Tutor 조건은 답 대신 힌트를 제공해 학습자의 작업을 남겨 둔 사례로, 숙련목표와 인터페이스 설계를 연결한다.

2.2 생성 효과: 먼저 스스로 만들어 보기

생성 효과(generation effect)는 정보를 단순히 읽은 경우보다 학습자가 직접 답, 설명, 단서 또는 예시를 만들어 본 경우 기억이 더 잘 되는 현상이다. Bertsch 외(2007)는 86개 연구의 445개 효과크기를 종합해 생성 조건의 평균 이점(d = 0.40)을 보고했다.

AI가 첫 초안과 답을 먼저 제공하면 학습자는 읽고 승인하는 위치에 머물 수 있다. 반대로 AI를 열기 전에 자신의 가설과 초안을 만들면, AI의 제안이 기존 사고와 비교할 수 있는 자료가 된다.

프로토콜 연결: 5장 1단계 자기 생성은 작업을 먼저 점유하는 단계다. Lira와 Bauer는 학습자가 직접 생성하지 않아도 산출물 품질이 좋아질 수 있음을 보여 주므로, 생성 효과는 산출물 품질이 아니라 학습자가 수행한 작업과 무보조 전이를 설명하는 원리로 사용한다. 배경지식이 거의 없는 초보자에게는 짧은 설명과 예시가 먼저 필요할 수 있다.

2.3 인출 연습과 시험 효과: 알고 있다고 느끼는 것과 꺼내는 것은 다르다

인출 연습(retrieval practice)은 자료를 다시 보는 대신 기억에서 내용을 꺼내는 연습이다. Roediger & Karpicke(2006)는 반복 학습보다 반복 시험이 지연된 기억 유지에 더 유리할 수 있음을 보였다. 즉시 시험에서는 재학습이 더 좋아 보일 수 있지만, 며칠 뒤 평가에서는 인출 연습의 이점이 나타났다.

AI 학습에서는 다음이 인출 연습에 해당한다.

  • AI와 대화하기 전에 자신의 답을 먼저 적기
  • AI 사용 후 화면을 닫고 핵심 개념을 설명하기
  • AI가 작성한 코드를 보지 않고 핵심 로직을 다시 구현하기
  • 다음 날 같은 원리를 새로운 문제에 적용하기

프로토콜 연결: 5장 1단계와 4단계, 5단계에서 AI 사용 직후의 유창한 이해감보다 지연된 무보조 회상을 우선한다. Bastani 외(2025)의 AI 제거 후 시험은 이 구분을 적용한 실증 사례다.

2.4 바람직한 어려움: 쉬운 수행이 항상 좋은 학습은 아니다

바람직한 어려움(desirable difficulties)은 학습 중에는 수행을 어렵게 만들지만 장기 유지와 전이에 도움이 될 수 있는 조건을 말한다(Bjork & Bjork, 2011). 간격 학습, 인출, 교차 연습 등이 대표적인 예다.

AI는 어려운 부분을 빠르게 제거한다. 이것은 작업 효율에는 좋지만, 학습에 필요한 생성·회상·오류 수정의 기회를 줄일 수 있다. 따라서 모든 어려움을 제거하기보다, 학습 목표에 필요한 어려움은 남겨야 한다.

프로토콜 연결: 5장 4단계의 무보조 전이와 5단계의 지연 확인에서 AI의 도움을 받은 과제와 AI 없이 확인하는 과제를 구분한다. Kosmyna 외(2025)의 조건 전환은 먼저 수행한 작업이 이후 AI 사용의 관여와 관련될 가능성을 보여 주지만, EEG를 학습 성과로 해석하지는 않는다.

2.5 인지적 외주화와 유창성 착각

인지적 외주화(cognitive offloading)는 기억·계산·계획 같은 처리를 외부 도구에 맡겨 인지 부담을 줄이는 것이다. Risko & Gilbert(2016)은 외주화가 유용한 적응 전략인 동시에, 무엇을 외부에 맡겼는지와 그 결과를 내부적으로 얼마나 이해하는지가 중요하다고 설명한다.

AI의 유창한 답변은 처리 부담을 줄이고 결과물을 빠르게 만든다. 그러나 읽기 쉽고 설명이 매끄럽다는 느낌이 실제 인출·적용 능력으로 이어진다는 보장은 없다. 이것이 유창성 착각(illusion of fluency)과 메타인지적 판단 오류의 위험이다(Koriat & Ma'ayan, 2005).

Shen & Tamkin(2026)은 AI 집단이 과제를 더 쉽게 느꼈지만 통제 집단이 자기보고한 학습은 더 높았다고 보고했다. 이는 “쉬웠다”는 경험과 “배웠다”는 판단이 분리될 수 있음을 보여 주는 직접적인 사례다.

프로토콜 연결: 5장 2단계의 질문·검증, 4단계의 무보조 전이, 5단계의 지연 확인에서 자기보고 난이도 대신 실제 설명·회상·전이 결과를 본다.

2.6 동료 튜터링: 배우고 가르치며 역할을 교대하기

동료 튜터링(peer tutoring)은 학습자들이 동료에게 배우고 동료를 가르치며 튜티와 튜터의 역할을 교대하는 상호적 학습 구조다. 튜티는 설명을 듣고 질문하며 오해를 드러내고, 튜터는 설명·응답·재구성을 하면서 자기 이해의 빈틈을 발견한다.

Roscoe & Chi(2007)는 튜터의 학습이 단순한 지식 전달보다 설명을 정교화하고 질문에 응답하며 기존 지식을 재구성하는 과정에서 나타난다고 분석했다. Shahriar & Matsuda(2023)는 teachable agent가 지식 전달식 응답을 보일 때 후속 질문을 제공하는 Constructive Tutee Inquiry를 제안했고, 처치 집단이 더 나은 성과를 보였으며 시간이 지나면서 후속 질문 없이도 knowledge-building에 참여하게 됐다고 보고했다.

실제 사람 동료와 상호작용할 수 있다면 서로 배우고 역할을 교대하는 활동을 우선한다. 동시에 AI를 연습용 튜티, 질문 생성기, 설명 피드백 도구, 실제 동료 토론을 준비하는 보조 동료로 만들 수 있다. AI의 질문과 피드백은 학습자가 검증한다.

프로토콜 연결: 5장 2단계에서 동료 또는 AI 튜티에게 설명하고 질문에 답한 뒤, 4단계에서 상대의 도움 없이 다시 설명한다. Constructive Tutee Inquiry의 후속 질문 없이도 knowledge-building에 참여하게 된 결과는 이 무보조 전이와 대응한다. 실제 동료를 쓸 때는 역할을 교대하고, AI를 쓸 때는 AI를 튜티 역할에 한정하되 핵심 설명과 최종 판단은 학습자가 담당한다.

3. AI 실증 연구: 어떤 사용이 어떤 결과를 만드는가

이 장은 두 렌즈로 읽는다. 첫째, 사람 중심 렌즈로 각 연구에서 학습자가 얼마나 인지적 작업을 했고 무엇을 외주화했는지를 본다. 둘째, 측정 대상 렌즈로 결과가 무보조 역량인지, 산출물 품질인지, 인지 관여의 대리 지표인지 구분한다. 3.1과 3.2는 주로 AI 제거 후 역량을, 3.3~3.5는 주로 인지 관여 또는 산출물 품질을 측정했다.

Bastani에서는 GPT Base가 작업을 대신하게 해 무보조 시험이 하락했고 GPT Tutor는 학습자의 작업을 남겨 손실을 완화했다. Shen & Tamkin에서는 완전 위임이 학습 손실과 연결됐고, 인지적 관여를 동반한 질적 패턴은 학습을 보존할 가능성을 보였다. Kosmyna에서는 먼저 스스로 쓴 집단이 이후 AI 사용에서 관여 지표가 상승했지만, 먼저 AI를 쓴 집단은 나중에 혼자 써도 낮은 관여 지표가 지속됐다. 이 세 연구는 학습자가 수행한 작업과 결과의 관계를 직접 다룬다.

반면 Lira와 Bauer에서는 학습자가 거의 작업하지 않아도 산출물은 좋아졌지만, 그 자체로 학습을 측정한 것은 아니다. 이 두 연구는 예시 노출이 특정 과제의 산출물을 개선할 수 있다는 경계 조건이면서, 산출물 품질만으로 학습을 추론할 수 없다는 증거다.

3.1 수학: 무제한 도움은 연습 성과를 높였지만 학습을 약화시킬 수 있다

Bastani 외(2025)는 고등학생 약 1,000명을 대상으로 GPT-4 기반 튜터를 비교했다. 일반적인 ChatGPT와 유사한 GPT Base, 학습을 보호하도록 설계된 GPT Tutor, 통제 조건이 포함됐다.

AI가 있는 동안에는 연습 성과가 올랐다. 그러나 AI를 제거한 시험에서는 GPT Base 집단이 통제 집단보다 낮은 성과를 보였고, 연구 초록은 그 차이를 17% 감소로 보고한다. GPT Tutor에서는 부정적 효과가 크게 완화됐다.

이 연구는 AI가 나쁘다는 근거가 아니다. 답을 대신 주는 인터페이스와 힌트·사고를 유도하는 인터페이스가 학습 결과를 다르게 만든다는 근거다. 연구는 고등학교 수학 맥락에 한정되며, 2025년 정정 이력도 함께 확인해야 한다.

출처: PNAS 원문, 정정 정보

3.2 코딩: AI 사용은 평균 효율도 자동으로 높이지 않았고, 위임형 사용은 학습을 약화시켰다

Shen & Tamkin(2026)은 주로 주니어인 개발자 52명을 대상으로, 처음 사용하는 Python 비동기 라이브러리를 학습할 때 AI 도움의 효과를 무작위 실험으로 조사했다.

원 논문의 핵심은 단순히 “AI가 편리했지만 학습이 줄었다”가 아니다.

  • AI 사용은 개념 이해, 코드 읽기, 디버깅을 저해했다.
  • 평균적으로 유의미한 효율 향상도 나타나지 않았다.
  • AI 없이 수행한 집단과 AI 집단의 속도 차이는 질의를 작성하고 응답을 읽고 이해하는 데 쓴 시간으로 상쇄될 수 있었다.
  • 과제를 완전히 위임한 참가자만 일부 생산성 이득을 보였지만, 그 대가로 해당 라이브러리의 학습을 잃었다.
  • AI 집단은 과제를 더 쉽게 느꼈지만, 통제 집단은 자기보고 학습을 더 높게 보고했다.

따라서 이 연구는 “단기 성과는 오르지만 장기 역량은 별개”라는 주장보다 강한 근거다.

AI 사용이 단기 성과를 자동으로 높인다는 보장조차 없다.

이 결과는 인지적 외주화와 유창성 착각에 연결된다. 작업은 쉬워졌다고 느끼지만, 실제로 무엇을 배웠는지에 대한 판단은 부정확할 수 있다. 다만 표본이 작고 하나의 라이브러리와 주로 주니어 개발자에 한정되며, 연구는 arXiv 프리프린트다.

출처: How AI Impacts Skill Formation (v2, 2026-02-01)

3.3 글쓰기: 먼저 쓴 뒤 AI를 사용한 조건에서 인지 관여가 높아졌다

Kosmyna 외(2025)의 MIT 연구는 GPT-4o, 검색엔진, 외부 도구 없는 글쓰기를 비교하고, 네 번째 세션에서 조건을 일부 바꾸었다. 54명이 첫 세 세션에 참여했고 네 번째 세션 완료자는 18명이었다.

Brain-only 집단은 더 강하고 넓은 EEG 연결성을 보였고, LLM 집단은 자기 글을 기억하고 인용하는 데 어려움을 보였다. 네 번째 세션에서 기존 Brain-only 집단이 LLM을 사용했을 때는 인지 연결성과 기억 회상이 증가했지만, 기존 LLM 집단이 AI 없이 작성할 때는 낮은 관여 지표가 지속됐다. 이 비대칭은 순서 효과의 가능성을 시사하지만, 어느 방향이 일반적으로 우월하다고 확정하지는 않는다.

이 연구의 EEG는 학습 그 자체가 아니라 인지 관여의 대리 지표다. 표본이 작고 동료심사 전 프리프린트이므로, “AI를 나중에 쓰면 글 점수가 더 좋아진다”가 아니라 먼저 자기 생각을 만든 뒤 AI를 도입하는 순서가 인지적 관여를 높일 가능성으로 제한해 해석한다.

출처: arXiv 원문, MIT 연구 페이지

3.4 글쓰기의 경계 조건: 좋은 예시 노출만으로도 산출물이 향상될 수 있다

Lira 외(2025)는 참가자들이 AI와 함께 커버레터 작성 연습을 한 뒤 하루 후 글쓰기 평가를 받는 사전등록 실험을 수행했다. AI 연습 집단은 AI 없이 연습한 집단보다 더 큰 산출물 품질 향상을 보였다. 이 연구는 무보조 역량이나 장기 전이를 직접 측정한 연구가 아니다.

두 번째 실험에서 AI와 직접 상호작용한 집단은 AI가 만든 커버레터를 보기만 한 집단보다 낫지 않았다. 따라서 관찰된 효과가 대화·질문이라는 상호작용 자체보다 고품질 예시 노출에서 왔을 가능성을 배제할 수 없다.

이 결과는 4장 조건부 모델에 중요한 경계 조건을 준다. 예시 노출은 독립된 학습 원리라기보다, 학습자가 수행해야 할 작업이 줄어도 산출물이 좋아질 수 있음을 보여 주는 사례다.

  • 예시의 구조와 표현을 배우는 과제에서는 예시 노출만으로도 충분할 수 있다.
  • 개념적 추론, 디버깅, 전이처럼 자기 판단이 핵심인 과제에서는 예시만 보는 것으로 부족할 수 있다.

연구는 커버레터라는 특정 과제에 관한 것이며, 장기 전이와 다른 글쓰기 과제에 대한 일반화에는 한계가 있다.

출처: Harvard Kennedy School 요약, arXiv 원문

3.5 학술 글쓰기: 예시 노출 경로와 비AI → AI → 비AI 순서의 가능성

Bauer 외(2026)는 베를린 소재 1학년 국제 패션디자인 전공생 21명(25명 모집, 4명 제외)을 대상으로, 2023년 5월 실험 인터페이스에 GPT-3.5 API를 내장해 학술 논문 서론을 다음 순서로 작성하게 했다.

비AI 글쓰기 → 내장형 GPT-3.5 사용 → 다시 비AI 글쓰기

AI 사용 조건에서 글의 품질이 높아졌고 이후 비AI 글쓰기에서도 첫 번째보다 품질이 높았다. 최종 텍스트의 평균 71%가 ChatGPT 출력에서 직접 복사되었고 중앙값은 95%였지만, 후속 비AI 글쓰기의 품질은 향상됐다. 저자들은 ChatGPT 출력이 과제에 맞춤화된 worked example(작업 예시)처럼 기능했을 가능성을 해석으로 제시한다. 또한 AI 사용 후 텍스트 분포의 이상치가 줄고 중앙으로 몰리는 균질화가 관찰되었으며, 약한 학생은 이득을 얻고 상위권 학생은 방해받았을 가능성도 제시됐다.

소유감은 ChatGPT 사용 중 유의하게 낮아졌지만(d = −0.52, p = .014), 이후 비AI 글쓰기에서 첫 번째보다 높아진 결과는 유의하지 않은 상승 경향이었다(d = 0.30, p = .095). 따라서 후속 소유감 상승을 확정적 효과로 쓰지 않는다.

이 연구는 AI 사용 후의 비AI 수행을 직접 다룬다는 장점이 있다. 그러나 대조군이 없는 ABA 내참가자 설계라 자연스러운 연습 효과와 AI 효과를 완전히 분리할 수 없다. 데이터 수집은 2023년 5월에 이루어졌고, 다중비교 보정이 적용되지 않아 저자들도 결과를 잠정적으로 해석한다. 또한 2026년의 최신 모델과 GPT-3.5 내장 인터페이스는 능력과 사용 경험이 다르므로, 현재의 ChatGPT·GPT 계열에 그대로 일반화하기 어렵다.

Lira와 Bauer는 모두 상호작용 자체보다 고품질·맞춤형 예시 노출이 산출물 개선의 일부를 설명할 수 있다는 공통 경계 조건을 제공한다. 두 연구는 후속 무보조 역량을 충분히 측정하지 않았으므로, 예시만으로 전이와 판단 능력까지 확보됐다고 해석하지 않는다.

출처: Computers and Education: Open

4. 통합 모델: 남겨야 할 작업을 숙련도와 과제로 결정하기

앞 장의 결과를 설계 규칙으로 바꾸면 두 축이 나온다. 숙련도는 학습자가 AI 출력을 판단할 수 있는가의 문제이고, 과제 유형은 이번 과제에서 생성·판단·무보조 적용을 실제로 해야 하는가의 문제다. 초보자는 AI 결과를 평가할 내부 스키마가 약하므로 더 많은 작업을 남겨야 하고, 숙련자는 반복 작업을 더 많이 외주화할 수 있다. 다만 새 도메인을 배우는 순간에는 숙련자도 학습형 과제로 돌아간다.

4.1 1차 분기: 나는 이 영역의 초보자인가

Bastani 연구는 고등학생, Shen & Tamkin 연구는 주로 주니어 개발자를 대상으로 했다. 이들은 AI 출력의 품질을 평가할 스키마가 충분하지 않을 수 있다. 다만 Bauer와 Lira의 결과가 보여 주듯 초보자에게 AI가 산출물 품질의 이득을 줄 수도 있다. 여기서 모순은 없다. Bastani와 Shen & Tamkin은 AI를 제거한 뒤의 학습·무보조 역량을 측정했고, Bauer와 Lira는 주로 AI 사용 중 또는 직후의 산출물 품질을 측정했다. 초보자에게서 결과물은 좋아져도 내부 역량이 같은 정도로 형성된다고 볼 수는 없다.

반면 해당 영역의 숙련자는 AI 출력을 빠르게 검토하고, 오류를 찾아내고, 자신의 기존 지식과 대조할 가능성이 크다. 그렇다고 숙련자에게 위험이 없는 것은 아니다. 익숙한 과제의 자동화가 새로운 영역의 학습을 방해할 수 있기 때문이다.

프로토콜을 적용하기 전 다음을 묻는다.

  • 내가 이 영역의 핵심 개념을 AI 없이 설명할 수 있는가?
  • 좋은 답과 그럴듯하지만 틀린 답을 구분할 수 있는가?
  • 실패 원인을 스스로 가설화할 수 있는가?

하나라도 자신 없으면 초보자 티어를 적용한다.

4.2 2차 분기: 이 과제는 어떤 작업을 요구하는가

  • 학습형: 개념 이해, 디버깅·추론, 새로운 기술 습득이 목적이다. 자기 생성, 질문, 인출과 오류를 직접 다루는 작업을 남긴다.
  • 반복형: 이미 익힌 절차를 반복하거나 자동화하는 업무다. 핵심 판단과 위험 지점은 직접 확인하되, 예시·표현 다듬기 같은 주변 작업은 위임할 수 있다.
  • 일회성: 장기 역량보다 당장의 전달물이 우선인 과제다. 예시·표현 학습과 결과 품질이 중심일 수 있지만, 사실·논리·보안·저작권 검증은 남긴다.

그러므로 모든 과제에 같은 AI 학습 프로토콜을 적용하지 않는다.

4.3 조건부 사용 모델

이 세 사용 방식은 4.2의 과제 유형에 적용하는 작업 배분이다. 대행형은 작업을 전부 넘기고, 예시형은 작업을 줄여 예시로 대체하며, 증폭형은 작업을 남긴 채 AI를 붙인다.

대행형 위임

문제를 이해하기 전에 AI에게 완성 답안·코드·글을 요청하고, 결과를 검증하지 않는 방식이다. 초보자에게 특히 위험하다.

예시형 사용

AI가 만든 고품질 예시를 읽고 구조, 기준, 표현을 분석하는 방식이다. Lira의 예시 노출 조건과 Bauer의 worked example 해석은 이 경로를 지지한다. 예시를 배우는 과제에서는 상호작용 없이도 충분한 효과가 있을 수 있지만, 그 자체가 전이와 판단 능력을 보장하지는 않는다.

증폭형 사용(augmentation)

학습자가 먼저 자기 생각을 만들고, AI를 질문·반례·피드백·비교·예시 도구로 사용하는 방식이다. 현재 근거가 지지하는 가장 유망한 설계지만, 모든 과제에서 다른 방식보다 우월하다고 확정된 것은 아니다.

5. 티어형 AI 보조 학습 프로토콜

0단계: 학습 목표 확인

이번 과제가 숙련목표를 포함하는지, 단순한 결과 제출인지 판단한다.

  • 숙련목표가 있으면 아래 프로토콜을 적용한다.
  • 일회성 결과 제출이고 재사용·전이가 중요하지 않으면 축약 티어를 사용한다.
  • 초보 영역이면 최소한 무보조 확인 단계를 남긴다.

0단계 이후의 티어 매핑

0단계에서 정한 숙련도와 과제 유형을 다음 기본값에 대입한다. 표는 선택을 돕는 지도이지 고정 규칙이 아니다.

숙련도 \ 과제 유형 학습형 반복형 일회성
초보 1티어 2티어의 단축 진입로 3티어 + 무보조 핵심 확인
숙련 1티어 또는 선택적 2티어 2티어 3티어

반복형 업무라도 새 도메인을 배우는 중이면 초보·학습형으로 취급한다.

1티어: 초보·숙련자 모두의 학습형 과제

개념 학습, 코딩 학습, 자격시험, 반복적으로 사용할 기술에 적용한다. 자기 생성은 작업을 먼저 점유하는 단계다.

  1. 자기 생성: AI를 열기 전에 문제, 가설, 초안 또는 해결 방향을 만든다.
  2. AI 대화: 답 대신 힌트, 반례, 예시, 질문, 비교를 요청한다. 예를 들면 다음과 같이 쓸 수 있다.
    • “내 설명을 모르는 학생처럼 듣고, 이해되지 않는 부분을 한 번에 하나씩 질문해 줘.”
    • “내 가설의 약한 부분과 반례가 될 수 있는 조건을 먼저 찾아 줘. 정답을 바로 제시하지 마.”
    • “정답이나 완성 코드는 말하지 말고, 다음 단계로 갈 수 있는 힌트만 한 번에 하나씩 줘.”
    • “이 해결 방법과 대안의 장단점을 비교하되, 어떤 것을 선택할지는 내가 판단할 수 있게 기준을 먼저 제시해 줘.”
  3. 판단·통합: 채택·수정·거부한 제안과 이유를 기록한다. 판단만은 넘기지 않는다.
  4. 무보조 전이: AI를 닫고 설명, 재구현, 디버깅 또는 변형 문제를 수행한다. 작업 능력을 검증하는 단계다.
  5. 지연 확인: 하루 또는 며칠 뒤 같은 원리를 새 문제에 적용한다.

2티어: 숙련자의 반복형 과제 또는 초보자의 저위험 반복 업무

숙련자는 이미 충분한 스키마가 있고 결과 검증 비용이 낮을 때 이 티어로 들어간다. 초보자는 반복 업무의 구조가 단순하고 즉시 검수할 수 있을 때만 이 단축 진입로를 쓴다.

  • 자기 생성은 짧은 가설이나 성공 기준으로 대체한다.
  • AI에게 초안·자동화·대안을 요청한다.
  • 핵심 판단과 위험 지점만 직접 검증한다.
  • 새로운 패턴이나 낯선 부분만 무보조로 재현한다.

3티어: 숙련자의 일회성 과제 또는 초보자의 결과 우선 과제

장기 역량보다 당장의 전달물이 중요한 경우다.

  • 1단계 자기 생성으로 목적과 성공 기준을 먼저 정한다.
  • AI로 결과물을 만든다.
  • 핵심 사실·논리·보안·저작권만 검증한다.
  • 초보자라면 결과물에서 재사용할 핵심 개념 하나를 AI 없이 설명하거나 재현한다.

매번 전체 인출 연습을 할 필요는 없지만, 이후 재사용할 핵심 지식은 별도로 남긴다.

이 프로토콜을 쓰지 않아도 되는 경우

  • 학습이 목표가 아닌 단순 변환·서식·반복 작업
  • 오류 비용이 낮고 결과를 즉시 검수할 수 있는 일회성 작업
  • 이미 충분한 숙련이 있고, 과제 자체가 새로운 역량을 요구하지 않는 작업
  • AI 없이 다시 수행하는 것이 업무 목적과 무관한 경우

다만 안전, 법률, 의료, 보안, 교육 평가처럼 결과의 책임과 장기 역량이 중요한 영역에서는 축약하더라도 검증과 책임 소재를 생략하지 않는다.

6. 평가 설계: AI를 잡아내기보다 학습을 드러내기

팀 리드나 교육 담당자라면, 지금부터는 개인 학습자의 사용법이 아니라 학습이 실제로 일어났는지를 드러내는 평가 설계를 함께 마련해야 한다.

형성평가는 증거를 수집하고 해석해 다음 학습 행동을 바꾸는 순환이며(Wiliam & Black, 1996; Black & Wiliam, 2009), 생성형 AI 환경에서는 학습자가 결과물의 질을 스스로 판단하는 평가적 판단(evaluative judgement)도 중요하다(Bearman 외, 2024). 산출물 품질은 학습의 증거가 아니다. AI 사용 탐지와 학습 확인은 다른 문제이며, 결과물만 평가하면 AI가 대신한 성과와 학습자의 역량을 구분하기 어렵다.

학습을 드러내는 증거는 다음과 같다.

  • AI 사용 전 가설과 초안
  • 질문·수정·거부의 기록
  • AI 없는 설명 또는 재현
  • 변형 과제 수행
  • 다음 날의 지연 인출
  • 결과물의 선택과 판단에 대한 짧은 구두 설명

이 평가는 AI 사용을 무조건 제한하려는 것이 아니다. 학습자가 AI를 어떻게 사용했는지와 AI가 사라진 뒤 무엇을 할 수 있는지를 함께 평가하려는 것이다.

7. 결론: 학습자가 남겨야 할 작업

학습은 학습자가 생성·인출·어려움 통과·설명 같은 인지적 작업을 수행할 때 형성된다. AI가 그 작업을 대신하면 산출물은 좋아질 수 있어도 역량은 남지 않을 수 있다. 쉬웠다는 느낌과 배웠다는 사실은 분리되며, 산출물 품질만으로 학습을 추론할 수 없다.

그러므로 무엇을 AI에게 맡길지는 학습자의 숙련도와 과제 목표, 그리고 이번 과제에서 반드시 남겨야 할 작업으로 결정한다. 학습자는 먼저 스스로 만들고, 판단만은 직접 하며, 마지막에는 AI 없이 다시 해봐야 한다. 예시 노출은 특정 과제에서 산출물을 개선하는 경계 조건일 수 있지만, 그것을 후속 학습의 증거로 확대하지 않는다.

학습자는 AI보다 빨리 쓰거나 코딩하는 사람이 될 필요는 없다. AI가 만든 결과를 읽고, 질문하고, 검증하고, 수정하고, 책임질 수 있는 작업의 범위를 넓히는 것이 augmentation의 기준이다.

참고 문헌

AI의 다음 경쟁은 누가 가장 강한 모델을 만드는가에만 있지 않다. 더 많은 사용자가 더 많은 업무를 더 낮은 비용으로 완료하게 만드는가가 핵심이다.

Astra는 AI가 맡을 수 있는 업무의 상한을 높인다. AWS의 저가 중국·오픈 모델은 지능의 유통 가격을 낮춘다. M5 Ultra 512GB급 머신은 일부 사용자에게 지능을 클라우드에서 임대하는 대신 직접 소유할 선택지를 준다.

세 사례는 서로 다른 뉴스처럼 보이지만, 하나의 산업 변화를 가리킨다.

프런티어 지능은 위로 확장되고, 저가 모델은 옆으로 확산되며, 로컬 머신은 아래에서 독립성을 만든다.

한 줄 요약

AI 비용 경쟁은 토큰당 가격 경쟁에서 성공한 업무 하나를 완료하는 가장 싼 경로를 선택하는 경쟁으로 이동하고 있다.

Uber와 연결되는 성장 루프

지난 Uber 사례의 핵심은 사용자는 늘리고, 단위 비용은 줄인다였다. AI에서도 비슷한 루프가 만들어진다.

추론 비용 하락
  → 더 많은 사용자와 사용량
  → 더 많은 평가·자동화·운영 데이터
  → 라우팅·캐시·하니스·모델 효율 개선
  → 성공한 업무당 비용 하락
  → 다시 사용량 증가

다만 AI에서 늘려야 하는 것은 단순한 호출 수가 아니다. 실제로 완료된 업무와 사용자 가치를 늘려야 한다. 호출량만 늘고 재시도·검토·실패가 함께 늘면 비용 효율이 좋아진 것이 아니다.

세 사례가 맡는 역할

1. Astra — 지능의 상한을 높인다

Astra 관련 발표의 핵심은 AGI라는 명칭보다 다음 질문에 있다.

  • 장시간 자율 작업이 가능한가
  • 수학·과학 연구의 탐색 속도를 높이는가
  • 사이버 능력이 인간 통제 범위를 넘기 시작했는가
  • 모델 자체보다 에이전트 + 도구 + 실행 권한이 핵심 위험 단위가 되는가

Astra는 지능의 상한과 업무 자동화 범위를 보여주는 사례다. 그러나 성능 수치와 AGI 해석은 우선 공급자 발표와 공개 보도로 분류해야 하며, 독립 재현과 실제 업무 성과가 확인되기 전에는 확정적 사실로 쓰지 않는다.

2. AWS의 저가 중국·오픈 모델 — 지능의 유통 가격을 낮춘다

AWS Bedrock과 SageMaker는 Qwen·DeepSeek 계열을 비롯한 오픈웨이트 모델을 관리형 환경에서 제공하고 있다. AWS는 2026년 3월 여러 오픈 모델에 서버리스 파인튜닝도 추가했다. AWS 발표

중요한 점은 “중국 모델이 싸다”에서 끝나지 않는다.

  • 고급 모델의 일정 수준 이상 성능이 널리 공급됨
  • 차별화 기준이 모델명에서 가격·지연시간·통합성으로 이동
  • 기업은 모든 작업에 최고가 모델을 쓸 필요가 없어짐
  • 라우터가 작업 난도와 실패 비용에 따라 모델을 배분할 수 있음

관리형 클라우드에 올라왔다고 해서 데이터 거버넌스, 모델 편향, 공급망, 규제 문제가 자동으로 해결되는 것은 아니다. 제공자, 추론 리전, 데이터 보존, 사고 대응, 대체 모델을 따로 확인해야 한다.

3. M5 Ultra 512GB — 지능의 로컬 소유를 가능하게 한다

Apple은 M5 Ultra Mac Studio에 최대 512GB 통합 메모리와 1.2TB/s 메모리 대역폭을 제공한다고 발표했다. 512GB 구성은 2026년 10월 말 출시 예정으로 안내됐다. Apple 공식 발표

이 장비의 의미는 단순히 “더 빠른 Mac”이 아니다.

  • 민감한 데이터를 외부 API로 보내지 않을 수 있음
  • API 비용과 공급자 종속성을 줄일 수 있음
  • 소규모 팀이 대형 오픈 모델을 직접 실험할 수 있음
  • 반복적인 문서·검색·코드 보조 작업을 고정비로 처리할 수 있음

다만 512GB 메모리가 곧 높은 추론 속도를 의미하지는 않는다. 모델 크기, 양자화, 메모리 대역폭, 컨텍스트 길이, 동시 사용자 수, 소프트웨어 최적화를 함께 봐야 한다. 전력·감가상각·업데이트·운영 비용까지 포함하면 로컬이 항상 클라우드보다 싼 것도 아니다.

세 층으로 분화되는 AI 시장

  1. 프런티어 계층 — Astra급 모델. 높은 성공률과 넓은 자동화 범위를 제공하지만 비용과 접근 통제가 크다.
  2. 클라우드 상품 계층 — 중국·오픈 모델과 관리형 API. 충분한 성능을 낮은 단가와 높은 확장성으로 제공한다.
  3. 로컬 소유 계층 — M5 Ultra급 장비와 온프레미스 모델. 보안·독립성·고정비 예측 가능성을 제공한다.

실제 기업 구성은 하나를 고르는 방식보다 다음과 같은 하이브리드에 가까워질 가능성이 높다.

요청
  ↓
작업 분류·비용·보안 라우터
  ├─ 단순 분류·요약·대량 RAG → 저가 모델
  ├─ 일반 코딩·문서 작업 → 오픈·중간급 모델
  ├─ 복잡한 추론·고위험 판단 → 프런티어 모델
  └─ 민감 정보·반복 업무 → 로컬 모델
       ↓
결과 검증·재시도·감사 로그

핵심 경쟁력은 특정 모델을 고정하는 것이 아니라, 난도·민감도·SLA·실패 비용·예산에 따라 가장 싼 성공 경로를 선택하는 것이다.

측정 단위를 바꿔야 한다

토큰당 가격만 비교하면 중요한 비용을 놓친다. 다음 지표가 더 중요하다.

  • 성공한 업무 1건당 비용
  • 사용자당 유효 업무 완료 수
  • 사람의 수정·검토 시간
  • 실패율과 재시도 횟수
  • 평균·최악 지연시간
  • 데이터가 외부로 나간 비율
  • 모델 교체와 검증에 드는 전환 비용

예를 들어 저가 모델이 한 번에 성공하지 못해 다섯 번 호출된다면, 비싼 모델 한 번보다 총비용이 커질 수 있다. 반대로 프런티어 모델이 높은 성공률로 재작업을 줄이면 토큰 가격이 높아도 업무당 비용은 낮을 수 있다.

판단 기준: 사실과 해석을 분리하기

이 글에서 각 사례는 다음 네 칸으로 관리한다.

  • 사실: 누가 무엇을 발표·판매·제공했는가
  • 근거 강도: 공식 문서, 독립 보도, 커뮤니티 관찰 중 어디에 기반하는가
  • 검증 상태: 독립 재현·실제 업무 검증·학술 검증이 되었는가
  • 해석: 산업 구조에 대해 어떤 의미를 부여하는가

특히 근거가 아직 약함과 거짓임이 확인됨을 구분한다. Astra의 AGI 주장, 수학적 성과, M5 Ultra의 비용 우위는 서로 다른 검증 문제를 가진다.

결론

AI의 다음 승자는 가장 똑똑한 모델을 가진 기업이 아닐 수 있다. 사용자가 더 많은 업무를 맡기고, 시스템이 그 업무를 더 낮은 비용으로 성공시키며, 결과를 사람이 검증할 수 있게 만드는 기업이 유리하다.

Astra는 지능의 상한을 높인다. 저가 클라우드 모델은 지능의 가격을 낮춘다. M5 Ultra 같은 로컬 머신은 지능의 소유권을 넓힌다.

따라서 이 글의 최종 질문은 “AGI가 도착했는가?”가 아니다.

누가 지능을 가장 싸고, 안전하고, 검증 가능한 업무 성과로 바꾸는가?

참고 자료

Data Science를 학습하면서, 전처리에 많이 사용되는 groupby를 정리해본다. 예제 데이터는 아래를 가정한다.

import pandas as pd

df  # columns: SEASON, A, B, C  (SEASON은 반복되는 범주값)

1. 개요 — Series가 모여 DataFrame이 된다

1.1 Series = 값 배열 + 인덱스

Series는 1차원이고, 값과 라벨(인덱스)이 짝지어진 구조다.

s = pd.Series([10, 20, 30], index=['x', 'y', 'z'], name='A')
x    10
y    20
z    30
Name: A, dtype: int64
  • s.values → array([10, 20, 30])
  • s.index → Index(['x','y','z'])
  • s.name → 'A' (나중에 DataFrame의 열 이름이 된다)

1.2 DataFrame = 인덱스를 공유하는 Series들의 모음

df = pd.DataFrame({
    'A': pd.Series([10, 20, 30], index=['x','y','z']),
    'B': pd.Series([1.0, 2.0, 3.0], index=['x','y','z']),
})
     A    B
x   10  1.0
y   20  2.0
z   30  3.0

핵심은 축이 두 개라는 점이다.

구성요소 의미
df.index 행 라벨 (axis=0)
df.columns 열 라벨 (axis=1)
df['A'] 열 하나 → Series
df[['A','B']] 열 여러 개 → DataFrame
df.loc['x'] 행 하나 → Series (인덱스가 열 이름이 된다)

대괄호 하나(df['A'])와 둘(df[['A']])의 차이가 이후 전부에 영향을 준다. 하나는 Series, 둘은 DataFrame이다.

1.3 MultiIndex = 라벨이 여러 층

인덱스의 한 칸이 단일 값이 아니라 튜플인 경우다.

mi = pd.MultiIndex.from_tuples([('2022','A'), ('2022','B'), ('2023','A')],
                               names=['SEASON', 'VAR'])
SEASON  VAR
2022    A
        B
2023    A
  • mi.nlevels → 2
  • level=0 → 바깥층(SEASON), level=1 → 안쪽층(VAR)
  • 이름이 있으면 숫자 대신 이름 사용 가능: level='SEASON'

groupby의 결과나 corr(), describe(), pivot 계열은 MultiIndex를 자주 만들어낸다. 그래서 "층을 어떻게 골라내고 없애느냐"가 실무의 대부분이다.


2. groupby 개요

2.1 split - apply - combine

df.groupby('SEASON')['A'].mean()
  1. split — SEASON 값이 같은 행끼리 묶는다
  2. apply — 각 묶음에 mean()을 적용한다
  3. combine — 결과를 다시 하나로 합친다. 그룹 키가 결과의 인덱스가 된다
SEASON
2022    18.3
2023    21.7
Name: A, dtype: float64

2.2 groupby 객체 자체는 계산을 하지 않는다

g = df.groupby('SEASON')
g                       # <DataFrameGroupBy object ...>  ← 아직 아무것도 안 함
g.ngroups               # 그룹 개수
g.size()                # 그룹별 행 수
g.groups.keys()         # 그룹 키 목록
g.get_group('2022')     # 특정 그룹의 원본 행들
list(g)[0]              # ('2022', DataFrame) 튜플

집계 함수(mean, agg, sum 등)를 붙이는 순간 실제로 계산된다. 디버깅할 때 get_group으로 한 그룹만 꺼내 확인하는 습관이 유용하다.

2.3 반환 형태 규칙

df.groupby('SEASON')['A'].mean()          # Series      (열 하나 → 1차원)
df.groupby('SEASON')[['A']].mean()        # DataFrame   (대괄호 둘)
df.groupby('SEASON')[['A','B']].mean()    # DataFrame
df.groupby(['SEASON','TEAM'])['A'].mean() # Series, 인덱스는 MultiIndex

2.4 자주 쓰는 옵션

df.groupby('SEASON', as_index=False)   # 그룹 키를 인덱스가 아닌 일반 열로
df.groupby('SEASON', sort=False)       # 그룹 키 정렬 안 함 (등장 순서 유지, 약간 빠름)
df.groupby('SEASON', dropna=False)     # 키가 NaN인 행도 하나의 그룹으로
df.groupby('SEASON', observed=True)    # Categorical 키에서 실제 등장한 조합만

as_index=False를 안 썼다면 나중에 .reset_index()로 같은 효과를 낼 수 있다.

2.5 agg / transform / apply 구분

셋의 차이를 헷갈리면 이후가 전부 꼬인다.

메서드 그룹당 반환 결과 행 수 용도
agg 스칼라 1개 그룹 수 평균, 합, max-min
transform 원본과 같은 길이 원본 행 수 그룹평균 붙이기, 정규화
apply 자유 (스칼라/Series/DataFrame) 상황에 따라 복잡한 그룹 로직
# agg: 시즌별 평균 (행 수 = 시즌 수)
df.groupby('SEASON')['A'].mean()

# transform: 각 행에 자기 시즌 평균을 붙인다 (행 수 = 원본)
df['A_season_mean'] = df.groupby('SEASON')['A'].transform('mean')
df['A_z'] = df.groupby('SEASON')['A'].transform(lambda s: (s - s.mean()) / s.std())

# apply: 여러 열을 동시에 봐야 할 때
df.groupby('SEASON').apply(
    lambda g: g['A'].corr(g['B']),
    include_groups=False,      # pandas 2.2+ 경고 방지
)

apply는 유연하지만 느리다. agg 또는 transform으로 표현 가능하면 그쪽을 쓴다.


3. groupby + corr 결과 인덱싱

3.0 만들어지는 구조 확인

c = df.groupby('SEASON')[['A', 'B', 'C']].corr()

문법 주의: df.groupby('SEASON').['A','B','C'] 는 오류. 대괄호를 두 번 쓴다 → [['A','B','C']]

                   A      B      C
SEASON  VAR
2022    A       1.00   0.35  -0.12
        B       0.35   1.00   0.48
        C      -0.12   0.48   1.00
2023    A       1.00   0.71   0.05
        B       0.71   1.00   0.22
        C       0.05   0.22   1.00
2024    A       1.00   0.19   0.60
        B       0.19   1.00  -0.33
        C       0.60  -0.33   1.00
  • 행 인덱스: (SEASON, VAR) 2층
  • 열: A, B, C
  • 시즌마다 3×3 대칭행렬이 세로로 쌓인 모양
  • 대각선은 항상 1.0, 상삼각과 하삼각은 중복. 실제 정보는 쌍 3개(A-B, A-C, B-C)뿐이다
c.index.names    # ['SEASON', None]
c.index[0]       # ('2022', 'A')

3.1 인덱스로 직접 접근 (loc)

스칼라 하나

c.loc[('2022', 'A'), 'B']      # 2022의 corr(A, B) → 0.35

행 라벨이 튜플이므로 ('2022','A')를 통째로 넘긴다.

한 시즌의 행렬 전체

c.loc['2022']
        A      B      C
VAR
A    1.00   0.35  -0.12
B    0.35   1.00   0.48
C   -0.12   0.48   1.00

바깥층은 전부, 안쪽층은 특정 값 — slice(None) 사용

c.loc[(slice(None), 'A'), :]     # 모든 시즌의 A행
c.loc[(slice(None), 'A'), 'B']   # 모든 시즌의 corr(A,B)

slice(None)이 눈에 거슬리면 IndexSlice가 같은 뜻이다.

idx = pd.IndexSlice
c.loc[idx[:, 'A'], 'B']
c.loc[idx['2022':'2023', 'A'], :]    # 시즌 범위 + 안쪽층 지정

이 방식의 결과는 인덱스가 여전히 2층이다.

c.loc[idx[:, 'A'], 'B'].idxmax()     # ('2023', 'A')  ← 튜플이 나온다

시즌 라벨만 원하면 [0]을 떼거나, 아래 xs를 쓴다.

MultiIndex 정렬 경고 loc에 슬라이스를 쓰다가 UnsortedIndexError가 나면 먼저 정렬한다.

c = c.sort_index()

3.2 xs로 단면 자르기

xs = cross-section. 지정한 층의 라벨이 일치하는 행만 골라내고, 그 층을 인덱스에서 제거한다.

c.xs('A', level=1)
          A      B      C
SEASON
2022   1.00   0.35  -0.12
2023   1.00   0.71   0.05
2024   1.00   0.19   0.60

동작을 두 단계로 풀면:

  1. VAR == 'A' 인 행만 남긴다 → 시즌당 1행
  2. VAR 층은 전부 'A'라 정보가 없으므로 인덱스에서 떨어뜨린다

읽는 법: "각 시즌에서 A가 다른 변수와 갖는 상관계수". A 열은 자기 자신이므로 항상 1.00이고, 쓸모 있는 건 B, C 열이다.

인덱스가 1층이 됐으므로 이후는 평범한 DataFrame이다.

c.xs('A', level=1)['B']
SEASON
2022    0.35
2023    0.71
2024    0.19
Name: B, dtype: float64

시즌별 corr(A,B) Series. idxmax, max, sort_values, plot 전부 그대로 동작한다.

c.xs('A', level=1)['B'].idxmax()    # '2023'  ← 튜플이 아니라 라벨

level을 생략하면 뜻이 달라진다

c.xs('A', level=1)   # 안쪽층(VAR)에서 'A' 찾기       ← 의도한 것
c.xs('2022')         # 바깥층(level=0 기본)에서 찾기   → 한 시즌 행렬
c.xs('A')            # 바깥층에서 'A'를 찾다가 KeyError

기본값이 level=0이므로 안쪽층을 노릴 때 level=1은 필수다.

층을 남기고 싶으면

c.xs('A', level=1, drop_level=False)

대칭성 상관행렬은 대칭이므로 어느 방향으로 뽑아도 값이 같다.

c.xs('A', level=1)['B']    # A행의 B열
c.xs('B', level=1)['A']    # B행의 A열 → 동일한 값

실전 조회 패턴

ab = c.xs('A', level=1)['B']   # 시즌별 corr(A, B)
ac = c.xs('A', level=1)['C']   # 시즌별 corr(A, C)
bc = c.xs('B', level=1)['C']   # 시즌별 corr(B, C)

s_best = ab.idxmax()           # corr(A,B) 최대 시즌
ab.max()                       # 그때의 corr(A,B) 값
ac.loc[s_best]                 # 그 시즌의 corr(A,C)
bc.loc[s_best]                 # 그 시즌의 corr(B,C)

bc.loc[ac.idxmax()]            # corr(A,C) 최대 시즌의 corr(B,C)
ab.nlargest(3)                 # corr(A,B) 상위 3시즌

3.3 unstack으로 평탄화 (flat)

무슨 일이 일어나는가

unstack()은 행 인덱스의 가장 안쪽 층을 뽑아 열로 올려붙인다. 시즌마다 3행이었던 것이 시즌마다 1행이 된다.

flat = c.unstack()
            A                     B                     C
VAR         A      B      C       A      B      C       A      B      C
SEASON
2022     1.00   0.35  -0.12    0.35   1.00   0.48   -0.12   0.48   1.00
2023     1.00   0.71   0.05    0.71   1.00   0.22    0.05   0.22   1.00
2024     1.00   0.19   0.60    0.19   1.00  -0.33    0.60  -0.33   1.00
  • 행 인덱스: SEASON 1층으로 줄었다
  • 열 인덱스: 2층으로 늘었다 (3 × 3 = 9개 열)
  • 층의 총 개수는 보존된다. 행에서 뺀 만큼 열로 옮겨갔을 뿐이다

열 튜플 읽는 규칙 (가장 헷갈리는 지점)

flat.columns
# MultiIndex([('A','A'), ('A','B'), ('A','C'),
#             ('B','A'), ('B','B'), ('B','C'),
#             ('C','A'), ('C','B'), ('C','C')])

(원래_열이름, 올라온_VAR값) — 기존 열이 겉층, 새로 올라온 층이 안층.

따라서 ('B','A') = "원래 표에서 VAR='A' 행의 B 열" = corr(A, B).

flat[('B', 'A')]     # 시즌별 corr(A, B)
flat['B']['A']       # 같은 것, 두 단계 접근
flat['B']            # B 겉층 전체 묶음

사람이 읽기 좋게 이름 붙이기

flat.columns = [f'{b}_{a}' for a, b in flat.columns]

a = 겉층(원래 열), b = 안층(VAR). 순서를 뒤집어 ('B','A') → 'A_B' 로 만든다.

A_A  B_A  C_A   A_B  B_B  C_B   A_C  B_C  C_C
 ↑                ↑                     ↑
1.0            corr(A,B)            corr(B,C)

대각선(A_A, B_B, C_C)은 1.0이고 B_A는 A_B의 중복이므로, 의미 있는 3개만 남긴다.

flat = flat[['A_B', 'A_C', 'B_C']]
        A_B    A_C    B_C
SEASON
2022   0.35  -0.12   0.48
2023   0.71   0.05   0.22
2024   0.19   0.60  -0.33

시즌이 행, 상관쌍이 열인 평범한 표가 됐다. 조회가 한 줄로 끝난다.

flat.loc[flat['A_B'].idxmax(), 'A_C']    # corr(A,B) 최대 시즌의 corr(A,C)
flat.loc[flat['A_C'].idxmax(), 'A_B']
flat.nlargest(3, 'A_B')                   # 상위 3시즌 전체 비교
flat.sort_values('B_C', ascending=False)
flat.corr()                               # 쌍끼리의 관계
flat.plot()                               # 시즌 추이 그래프

unstack(level=0) — 방향 반대

c.unstack(level=0)      # == c.unstack('SEASON')
          A                    B                 ...
SEASON  2022   2023   2024   2022   2023   2024
VAR
A       1.00   1.00   1.00   0.35   0.71   0.19
B       0.35   0.71   0.19   1.00   1.00   1.00
C      -0.12   0.05   0.60   0.48   0.22  -0.33

변수가 행, 시즌이 열. 시즌 수가 많으면 열이 폭발하므로 보통 기본값(VAR을 올리는 쪽)이 실용적이다.

역연산 stack

flat.stack()     # 열 층을 행으로 내린다 → 원래 c 모양에 가깝게 복귀

3.4 행렬을 거치지 않는 대안

corr()은 대각선과 중복을 모두 계산한다. 쌍 값만 필요하면 처음부터 직접 만드는 게 가볍고 명확하다.

pairs = df.groupby('SEASON').apply(
    lambda g: pd.Series({
        'A_B': g['A'].corr(g['B']),
        'A_C': g['A'].corr(g['C']),
        'B_C': g['B'].corr(g['C']),
    }),
    include_groups=False,
)
pairs.loc[pairs['A_B'].idxmax()]

또는 reset_index로 아예 긴 형태(long format)로 펴는 방법.

t = c.reset_index().rename(columns={'level_1': 'VAR'})
t.loc[t['VAR'] == 'A', ['SEASON', 'B', 'C']]

3.5 세 방식 비교

방식 결과 인덱스 idxmax() 반환 언제
loc / IndexSlice 2층 유지 튜플 ('2023','A') 스칼라 하나, 범위 슬라이싱
xs(..., level=1) 1층으로 축소 라벨 '2023' 특정 변수 기준 조회 (가장 흔함)
unstack + 이름정리 1층 + 열 평탄 라벨 '2023' 여러 쌍을 나란히 비교/정렬/시각화

4. groupby().agg() 사용법

4.1 named aggregation — 새컬럼명=(원본컬럼, 함수)

권장 기본형이다. 결과 열이 평평한 단일 레벨로 나와 후처리가 없다.

out = df.groupby('SEASON').agg(
    A_mean=('A', 'mean'),
    B_range=('B', lambda s: s.max() - s.min()),
)
        A_mean  B_range
SEASON
2022      18.3      7.2
2023      21.7      5.4

lambda 대신 이름 있는 함수를 쓰면 재사용과 가독성이 좋다.

def rng(s):
    return s.max() - s.min()

df.groupby('SEASON').agg(A_mean=('A', 'mean'), B_range=('B', rng))

한 열에 여러 집계, 서로 다른 열을 자유롭게 섞을 수 있다.

df.groupby('SEASON').agg(
    A_mean=('A', 'mean'),
    A_std=('A', 'std'),
    B_max=('B', 'max'),
    B_min=('B', 'min'),
    B_range=('B', rng),
    C_median=('C', 'median'),
    N=('A', 'size'),                       # 행 수 (NaN 포함)
    N_valid=('A', 'count'),                # 결측 제외 개수
    A_p90=('A', lambda s: s.quantile(0.9)),
)

제약: 키워드 인자 이름이므로 파이썬 식별자여야 한다. SALES 2023=(...) 같은 건 불가.

4.2 dict 방식 — agg({열: 함수})

df.groupby('SEASON').agg({'A': 'mean', 'B': rng})              # 단일 → 열이 평평
df.groupby('SEASON').agg({'A': ['mean', 'std'], 'B': [rng]})   # 다중 → 열이 MultiIndex

다중일 때 결과:

            A               B
         mean    std      rng
SEASON
2022     18.3    3.1      7.2

평탄화는 습관적으로 붙여두면 편하다.

g = df.groupby('SEASON').agg({'A': ['mean','std'], 'B': [rng]})
g.columns = ['_'.join(col) for col in g.columns]    # A_mean, A_std, B_rng
g = g.reset_index()

dict가 유리한 경우

1) 열이 많고 집계가 반복적일 때

num_cols = df.select_dtypes('number').columns
df.groupby('SEASON').agg({c: 'mean' for c in num_cols})

named agg로는 **{f'{c}_mean': (c,'mean') for c in num_cols} 언패킹이 필요해 장황하다.

2) 집계 스펙을 외부(설정/인자)에서 주입할 때

spec = {'A': 'mean', 'B': rng, 'C': ['min', 'max']}
df.groupby('SEASON').agg(spec)

3) MultiIndex 열을 그대로 활용할 때

g = df.groupby('SEASON').agg({'A': ['mean','std'], 'B': ['mean','std']})
g.stack(level=0)      # 변수 × 통계량 형태로 재배치
g['A']['mean']        # 계층 접근

named agg는 항상 1층이라 이런 재배치가 안 된다.

4) 열 이름이 파이썬 식별자가 아닐 때 — 'SALES 2023', '매출/원' 등

5) pivot_table의 aggfunc — named agg 문법 자체가 없다

df.pivot_table(index='SEASON', aggfunc={'A': 'mean', 'B': rng})

주의: dict 안에서 이름 바꾸기는 제거됐다

pandas 0.20 deprecated → 2.0 제거. 아래는 모두 에러다.

df.groupby('SEASON').agg({'A': {'평균': 'mean'}})     # ✗
df.groupby('SEASON')['A'].agg({'평균': 'mean'})       # ✗

이름을 정하려면 named agg를 쓰거나, dict로 집계한 뒤 rename한다.

4.3 Series에 대한 agg

열 하나만 다룰 때는 리스트로 넘기면 된다.

df.groupby('SEASON')['A'].agg(['mean', 'std', 'max', rng])
df.groupby('SEASON')['A'].agg(평균='mean', 범위=rng)    # Series named agg (가능)

4.4 자주 쓰는 집계 문자열

'mean' 'median' 'sum' 'min' 'max' 'std' 'var' 'count' 'size' 'first' 'last' 'nunique' 'idxmax' 'idxmin' 'any' 'all' 'sem' 'skew' 'prod'

문자열은 내부 최적화 경로를 타서 lambda보다 훨씬 빠르다. 가능하면 문자열을 쓴다.

  • count vs size: count는 NaN 제외, size는 포함
  • idxmax: 그룹 내 최대값의 인덱스 라벨을 돌려준다

4.5 두 방식 선택 기준

상황 선택
열 몇 개, 결과 이름을 명시하고 싶다 named agg
열을 동적으로 생성 / 스펙 주입 dict
MultiIndex 열로 후처리 (stack 등) dict
열 이름이 파이썬 식별자가 아니다 dict
pivot_table dict

한 agg 호출 안에서 두 방식을 섞을 수는 없다. 하나만 고른다.


5. 자주 밟는 함정

증상 원인 / 해결
df.groupby('S').['A','B'] 문법 오류 [['A','B']] 대괄호 두 번
xs('A')에서 KeyError level 기본값이 0. 안쪽층은 level=1 명시
idxmax()가 튜플을 반환 loc/IndexSlice는 층을 남긴다. xs나 unstack을 쓰거나 [0]으로 꺼낸다
UnsortedIndexError c = c.sort_index() 후 슬라이싱
unstack 후 열 접근 실패 튜플 순서는 (원래열, 올라온층). 이름 붙일 때 뒤집는다
agg 결과 열이 2층 dict + 다중 함수. '_'.join으로 평탄화
agg({'A': {'평균':'mean'}}) 에러 제거된 문법. named agg 사용
apply에서 그룹 키 관련 FutureWarning include_groups=False 추가 (pandas 2.2+)
np.ptp 사용 시 경고 직접 lambda s: s.max()-s.min() 정의
결과 행 수가 예상과 다름 agg(그룹 수) vs transform(원본 수) 혼동
그룹 키가 인덱스로 들어가 불편 as_index=False 또는 .reset_index()
키가 NaN인 행이 사라짐 기본 dropna=True. dropna=False

6. 한눈 치트시트

# 구조 확인
c.index.names / c.index.nlevels / c.columns

# 기본 집계
df.groupby('SEASON')['A'].mean()                       # Series
df.groupby('SEASON')[['A','B']].mean()                 # DataFrame
df.groupby('SEASON', as_index=False)['A'].mean()       # 키를 열로

# corr 결과 인덱싱
c = df.groupby('SEASON')[['A','B','C']].corr()
c.loc[('2022','A'), 'B']                               # 스칼라
c.loc['2022']                                          # 한 시즌 행렬
c.xs('A', level=1)                                     # A행만, 층 제거
c.xs('A', level=1)['B']                                # 시즌별 corr(A,B)
flat = c.unstack()
flat.columns = [f'{b}_{a}' for a, b in flat.columns]
flat = flat[['A_B','A_C','B_C']]

# 조회
ab, ac = flat['A_B'], flat['A_C']
ac.loc[ab.idxmax()]                                    # A_B 최대 시즌의 A_C
flat.nlargest(3, 'A_B')

# agg
df.groupby('SEASON').agg(A_mean=('A','mean'), B_range=('B', rng))
df.groupby('SEASON').agg({'A': ['mean','std'], 'B': [rng]})

# transform (원본 행 수 유지)
df['A_dev'] = df['A'] - df.groupby('SEASON')['A'].transform('mean')

+ Recent posts