diff --git a/README.md b/README.md index c84d574..c7ae92f 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Matheus Facure의 [Causal Inference for The Brave and True](https://matheusfacur 원서 DOI

-**[웹북으로 읽기](https://causalinferencelab.github.io/Causal-Inference-with-Python/)** · [용어집](https://causalinferencelab.github.io/Causal-Inference-with-Python/glossary.html) · [번역 가이드](TRANSLATION_GUIDE.md) · [오류 제보](https://github.com/CausalInferenceLab/Causal-Inference-with-Python/issues) +**[웹북으로 읽기](https://causalinferencelab.github.io/Causal-Inference-with-Python/)** · [인과추론 허브](https://causalinferencelab.github.io/) · [용어집](https://causalinferencelab.github.io/Causal-Inference-with-Python/glossary.html) · [번역 가이드](TRANSLATION_GUIDE.md) · [오류 제보](https://github.com/CausalInferenceLab/Causal-Inference-with-Python/issues)
@@ -35,6 +35,8 @@ Matheus Facure의 [Causal Inference for The Brave and True](https://matheusfacur 번역은 전문 번역가가 아니라 데이터 분석가, 데이터 과학자, 연구자들이 함께 했습니다. 용어는 『실무로 통하는 인과추론 with 파이썬』(한빛미디어)과 맞췄고, 핵심 용어는 처음 나올 때 영어를 함께 적었습니다. 어색한 문장이나 잘못된 번역을 발견하면 언제든 알려 주세요. +이 책은 인과추론팀의 오픈소스와 자료를 L0–L4 커리큘럼으로 엮은 [Causal Inference Hub](https://causalinferencelab.github.io/)의 L1 중심 자료입니다. [허브에서 이 책의 자리](https://causalinferencelab.github.io/#station=Causal-Inference-with-Python)를 열면 앞뒤로 이어지는 자료를 볼 수 있습니다. +
## 목차 diff --git a/book/_quarto.yml b/book/_quarto.yml index a503d03..ecaa661 100644 --- a/book/_quarto.yml +++ b/book/_quarto.yml @@ -13,9 +13,6 @@ execute: enabled: false book: - google-analytics: - tracking-id: "G-BEBVKYH8HL" - anonymize-ip: true title: "Python으로 하는 인과추론" subtitle: "Causal Inference for The Brave and True 한국어판" author: @@ -39,6 +36,7 @@ book: style: docked collapse-level: 3 header: | + Causal Inference Hub인과추론팀 커리큘럼과 오픈소스 가짜연구소 Pseudo Lab 가짜연구소 Pseudo Lab @@ -48,6 +46,8 @@ book: page-footer: left: "[가짜연구소](https://pseudo-lab.com/) 인과추론팀 옮김 · 원서 © [Matheus Facure](https://matheusfacure.github.io/python-causality-handbook/landing-page.html)" center: + - text: 인과추론 허브 + href: https://causalinferencelab.github.io/ - text: 번역 가이드 href: https://github.com/CausalInferenceLab/Causal-Inference-with-Python/blob/main/TRANSLATION_GUIDE.md - text: 오류 제보 @@ -115,13 +115,16 @@ format: html-math-method: mathjax df-print: default link-external-newwindow: true + link-external-filter: '^(?:https?:)\/\/causalinferencelab\.github\.io\/' back-to-top-navigation: true include-after-body: - sidebar-resize.html - chapter-toc.html - site-search.html + - reader.html - comments.html include-in-header: + - analytics.html - text: | diff --git a/book/analytics.html b/book/analytics.html new file mode 100644 index 0000000..b9ed928 --- /dev/null +++ b/book/analytics.html @@ -0,0 +1,19 @@ + + + diff --git a/book/index.qmd b/book/index.qmd index 4bd4c2f..d2f9526 100644 --- a/book/index.qmd +++ b/book/index.qmd @@ -7,17 +7,22 @@ aliases: ```{=html}
+
가짜연구소 Pseudo Lab 인과추론팀 Causal-Lab

Python으로 하는
인과추론

-

Causal Inference for The Brave and True 한국어판. 인과추론의 기초부터 실무 응용까지, 모든 실습을 파이썬으로.

+

Causal Inference for The Brave and True 한국어판. 인과추론의 기초부터 실무 응용까지, 모든 실습을 파이썬으로.

@@ -87,9 +92,34 @@ aliases: 1부는 학계에서 자리 잡은 내용이라 인과적 질문을 다룰 때 기댈 수 있는 튼튼한 토대가 됩니다. 2부는 저자가 핀테크 회사에서 쌓은 실무 경험에서 나온 내용이 많아 더 실험적이고, 그만큼 현업에 바로 가져다 쓸 거리가 많습니다. +## 인과추론 허브에서 이어 가기 + +```{=html} + + + + 가짜연구소 인과추론팀 + Causal Inference Hub + 웹북, 영상, 스터디 자료, 데이터 에이전트까지. 팀이 만든 오픈소스를 L0–L4 커리큘럼으로 엮었습니다. + + 허브 둘러보기 + +``` + +이 책은 가짜연구소 인과추론팀의 [Causal Inference Hub](https://causalinferencelab.github.io/)에 있는 자료입니다. 허브는 팀이 2022년부터 만든 오픈소스와 자료를 L0부터 L4까지 커리큘럼으로 엮어 둔 곳이고, 이 책은 L1('어떻게 추정하나')의 중심 자료입니다. 허브에서는 이 책을 'Brave & True 인과추론 번역서'로 소개합니다. + +인과추론이 처음이라면 L0의 [영상으로 여는 인과추론](https://causalinferencelab.github.io/causal-studio/)으로 먼저 감을 잡고 넘어와도 좋습니다. 책을 마친 뒤에는 관심에 따라 이렇게 이어 갈 수 있습니다. + +- 내 데이터에 적용해 보고 싶다면: [산업 사례 템플릿](https://causalinferencelab.github.io/#station=causal-inference-practice), [책 예제 코드](https://causalinferencelab.github.io/#station=causal-inference-in-python-code) +- 메타러너와 이중 머신러닝을 코드로 더 익히고 싶다면: ML 트랙의 [CausalML 스터디](https://causalinferencelab.github.io/#station=causal-inference-with-causalML) +- A/B 테스트를 제대로 하고 싶다면: 실험 트랙의 [온라인 통제 실험](https://causalinferencelab.github.io/#station=OCE-Materials) +- 헬스케어와 규제 연구가 궁금하다면: 연구 트랙의 [RWE 규제 가이드라인](https://causalinferencelab.github.io/#station=Bridging-Causal-Inference-and-Real-World-Evidence-A-Study-of-FDA-and-Other-Regulatory-Guidelines) + +각 장 끝에도 그 장 다음에 보면 좋은 허브 자료를 하나씩 붙여 두었습니다. 전체 흐름은 [허브에서 이 책의 자리](https://causalinferencelab.github.io/#station=Causal-Inference-with-Python)를 열어 보면 앞뒤 자료와 함께 한눈에 보입니다. + ## 이렇게 읽어 주세요 -각 장은 원서의 주피터 노트북을 그대로 옮긴 것이라 코드와 출력이 원서와 같습니다. 노트북 파일은 [GitHub 저장소](https://github.com/CausalInferenceLab/Causal-Inference-with-Python/tree/main/causal-inference-for-the-brave-and-true)에서 내려받아 직접 실행해 볼 수 있습니다. 그래프를 그리는 코드처럼 길어서 접어 둔 셀은 **코드**를 눌러 펼치면 됩니다. +각 장은 원서의 주피터 노트북을 그대로 옮긴 것이라 코드와 출력이 원서와 같습니다. 노트북 파일은 [GitHub 저장소](https://github.com/CausalInferenceLab/Causal-Inference-with-Python/tree/main/causal-inference-for-the-brave-and-true)에서 내려받아 직접 실행해 볼 수 있습니다. 그래프를 그리는 코드처럼 길어서 접어 둔 셀은 **코드**를 눌러 펼치면 됩니다. 끝까지 읽은 장은 왼쪽 목차에 ✓ 표시가 붙고, 다음에 오면 첫 화면에서 이어 읽을 수 있습니다. 이 기록은 지금 쓰는 브라우저에만 남습니다. 용어는 같은 저자의 책을 옮긴 『실무로 통하는 인과추론 with 파이썬』(한빛미디어)과 맞췄습니다. 두 책을 함께 보셔도 용어가 헷갈리지 않습니다. 용어의 원어와 그 용어를 다루는 장은 [용어집](glossary.html)에서 찾을 수 있습니다. 왼쪽 위 검색(단축키 `/` 또는 `Ctrl+K`)에 한국어나 영어 용어를 넣어도 됩니다. 띄어쓰기는 달라도 찾아 줍니다. 번역 원칙과 용어표는 [번역 가이드](https://github.com/CausalInferenceLab/Causal-Inference-with-Python/blob/main/TRANSLATION_GUIDE.md)에 정리해 두었습니다. diff --git a/book/reader.html b/book/reader.html new file mode 100644 index 0000000..0195a34 --- /dev/null +++ b/book/reader.html @@ -0,0 +1,251 @@ + diff --git a/book/site-search.html b/book/site-search.html index 0ae3567..01ee75a 100644 --- a/book/site-search.html +++ b/book/site-search.html @@ -17,6 +17,14 @@ var input = document.getElementById("cil-search-input"); var list = document.getElementById("cil-search-results"); var data = null, loading = null, items = [], active = -1, timer = 0; + var reported = ""; + // 무엇을 찾는지 GA4 'search' 이벤트로 남긴다(결과를 열 때, 또는 찾다가 닫을 때 한 번) + function report(how) { + var q = input.value.trim(); + if (norm(q).length < 2 || q === reported) return; + reported = q; + try { if (typeof window.gtag === "function") window.gtag("event", "search", { search_term: q, results: items.length, how: how }); } catch (e) {} + } var SUGGEST = ["잠재적 결과", "성향점수", "이중차분법", "도구변수", "평행 추세", "메타러너", "A/B 테스트"]; function norm(s) { @@ -133,6 +141,7 @@ } function close() { if (box.hidden) return; + report("close"); box.hidden = true; document.documentElement.classList.remove("cil-search-open"); input.blur(); @@ -150,14 +159,14 @@ else if (e.key === "ArrowUp") { e.preventDefault(); move(-1); } else if (e.key === "Enter") { var target = items[active >= 0 ? active : 0]; - if (target) { e.preventDefault(); window.location.href = target.getAttribute("href"); close(); } + if (target) { e.preventDefault(); report("open"); window.location.href = target.getAttribute("href"); close(); } } else if (e.key === "Escape") { close(); } }); box.addEventListener("click", function (e) { if (e.target.closest("[data-close]")) close(); var chip = e.target.closest("[data-q]"); if (chip) { input.value = chip.getAttribute("data-q"); render(input.value); input.focus(); } - if (e.target.closest(".cil-search-item")) close(); + if (e.target.closest(".cil-search-item")) { report("open"); close(); } }); document.addEventListener("keydown", function (e) { var typing = /^(INPUT|TEXTAREA|SELECT)$/.test(document.activeElement.tagName) || document.activeElement.isContentEditable; diff --git a/book/styles-dark.scss b/book/styles-dark.scss index c3b387f..f25b163 100644 --- a/book/styles-dark.scss +++ b/book/styles-dark.scss @@ -144,3 +144,88 @@ body { .ch-chip b { color: #c9bcf5; } + +.hub-card { + border-color: #2b2e40; + background: rgba(180, 165, 234, 0.1); + color: #eceaff; +} + +.hub-card:hover { + background: rgba(180, 165, 234, 0.18); + color: #eceaff; +} + +.hub-card .hub-card-arrow { + background: #1d1f2c; + color: #c9bcf5; +} + +.cil-hub-mobile { + background: rgba(180, 165, 234, 0.14); + color: #eceaff; +} + +.cil-chapter-meta { + color: #9a9db0; +} + +.cil-chapter-meta a { + color: #b4a5ea; +} + +.cil-chapter-meta .cil-read-badge, +#quarto-sidebar .sidebar-link.is-read .menu-text::after { + color: #6fcf97; +} + +.cil-end-row { + border-top-color: #2b2e40; +} + +.cil-end-vote .q { + color: #eceaff; +} + +.cil-end-vote button { + border-color: rgba(180, 165, 234, 0.3); + color: #e4e5ee; +} + +.cil-end-vote button[aria-pressed="true"] { + background: #b4a5ea; + border-color: #b4a5ea; + color: #14151f; +} + +.cil-end-vote .thanks, +.cil-end-progress { + color: #9a9db0; +} + +.cil-end-progress .bar { + background: rgba(180, 165, 234, 0.16); +} + +.hub-next { + border-color: #2b2e40; + background: linear-gradient(135deg, rgba(180, 165, 234, 0.12) 0%, #14151f 75%); +} + +.hub-next .hub-next-k { + color: #c9bcf5; +} + +.hub-next .hub-next-t { + color: #eceaff; +} + +.hub-next .hub-next-a a { + border-color: rgba(180, 165, 234, 0.35); +} + +.hub-next .hub-next-a a.primary { + background: #b4a5ea; + border-color: #b4a5ea; + color: #14151f; +} diff --git a/book/styles.scss b/book/styles.scss index 7e3a946..70cd32d 100644 --- a/book/styles.scss +++ b/book/styles.scss @@ -428,6 +428,472 @@ main:has(.hero) #title-block-header { text-align: center; } +// 사이드바 맨 위: Causal Inference Hub로 가는 카드 +.hub-card { + display: flex; + align-items: center; + gap: 0.6rem; + margin: 0.1rem 0 0.9rem; + padding: 0.5rem 0.75rem; + border-radius: 12px; + border: 1px solid rgba($indigo, 0.16); + background: $lavender-soft; + color: $navy; + text-decoration: none; + transition: border-color 0.15s ease, background-color 0.15s ease; +} + +.hub-card:hover { + border-color: rgba($indigo, 0.45); + background: rgba($lavender, 0.24); + color: $navy; +} + +.hub-card .hub-card-arrow { + display: grid; + place-items: center; + flex: none; + width: 1.7rem; + height: 1.7rem; + border-radius: 50%; + background: #fff; + color: $indigo; + font-weight: 700; + transition: transform 0.15s ease; +} + +.hub-card:hover .hub-card-arrow { + transform: translateX(-2px); +} + +.hub-card .hub-card-text { + display: flex; + flex-direction: column; + min-width: 0; + line-height: 1.3; +} + +.hub-card b { + font-size: 0.86rem; + font-weight: 750; +} + +.hub-card small { + font-size: 0.72rem; + color: $sidebar-fg; +} + +// 좁은 화면 상단 막대의 허브 바로가기 +.cil-hub-mobile { + display: inline-flex; + flex: none; + align-self: center; + align-items: center; + line-height: 1.2; + gap: 0.3rem; + margin: 0 0.15rem 0 0.4rem; + padding: 0.22rem 0.6rem 0.22rem 0.45rem; + border-radius: 999px; + background: $lavender-soft; + color: $navy; + font-size: 0.8rem; + font-weight: 700; + text-decoration: none; + white-space: nowrap; +} + +.cil-hub-mobile img { + width: 16px; + height: auto; + margin: 0; +} + +@media (min-width: 992px) { + .cil-hub-mobile { + display: none; + } +} + +// 첫 화면 위치 표시: 인과추론 허브 › 서가 +.hero .hero-crumb { + display: flex; + align-items: center; + gap: 0.45rem; + margin-bottom: 1.1rem; + font-size: 0.82rem; + color: rgba(255, 255, 255, 0.6); +} + +.hero .hero-crumb a { + color: rgba(255, 255, 255, 0.88); + font-weight: 600; + text-decoration: none; + border-bottom: 1px solid rgba(255, 255, 255, 0.35); +} + +.hero .hero-crumb a:hover { + color: #fff; + border-bottom-color: #fff; +} + +// 장 첫머리: 분량, 위치, 노트북 +.cil-chapter-meta { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 0.35rem 0.9rem; + margin: 0.55rem 0 0.2rem; + font-size: 0.84rem; + color: lighten($body-color, 30%); +} + +.cil-chapter-meta > * + *::before { + content: ""; + display: inline-block; + width: 3px; + height: 3px; + margin: 0 0.9rem 0.2em -0.55rem; + border-radius: 50%; + background: currentColor; + opacity: 0.5; + vertical-align: middle; +} + +.cil-chapter-meta a { + color: $indigo; + text-decoration: none; + font-weight: 600; +} + +.cil-chapter-meta a:hover { + text-decoration: underline; +} + +.cil-chapter-meta .cil-read-badge { + color: #2b8a5a; + font-weight: 700; +} + +// 읽기 진행 막대 +.cil-progress { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 1040; + height: 3px; + pointer-events: none; +} + +.cil-progress i { + display: block; + height: 100%; + background: linear-gradient(90deg, $indigo, $lavender); + transform: scaleX(0); + transform-origin: 0 50%; +} + +// 왼쪽 목차: 읽은 장 +#quarto-sidebar .sidebar-link.is-read .menu-text::after { + content: "✓"; + margin-left: auto; + padding-left: 0.4rem; + color: #2b8a5a; + font-size: 0.8em; + font-weight: 700; +} + +// 첫 화면: 이어 읽기와 진도 +.hero .hero-actions a.primary span { + font-weight: 500; + opacity: 0.8; +} + +.hero .hero-progress { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 0.4rem 0.7rem; + margin: 0.3rem 0 0; + font-size: 0.82rem; + color: rgba(255, 255, 255, 0.82); +} + +.hero .hero-progress a { + color: #fff; + font-weight: 600; + text-decoration: underline; + text-underline-offset: 3px; + text-decoration-color: rgba(255, 255, 255, 0.45); +} + +.hero .hero-sub a { + color: inherit; + text-decoration: underline; + text-underline-offset: 3px; + text-decoration-color: rgba(255, 255, 255, 0.4); +} + +.hero .hero-sub a:hover { + color: #fff; + text-decoration-color: #fff; +} + +.hero .hero-progress .bar { + flex: none; + width: 90px; + height: 5px; + border-radius: 999px; + background: rgba(255, 255, 255, 0.25); + overflow: hidden; +} + +.hero .hero-progress .bar i { + display: block; + height: 100%; + background: #fff; +} + +// 장 끝 마무리: 평가와 진도 +.cil-end { + margin-top: 2.8rem; +} + +.cil-end-row { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + gap: 0.8rem 1.4rem; + padding: 0.9rem 0; + border-top: 1px solid rgba($indigo, 0.15); +} + +.cil-end-vote { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 0.45rem; +} + +.cil-end-vote .q { + margin-right: 0.3rem; + font-weight: 700; + color: $navy; +} + +.cil-end-vote button { + padding: 0.32rem 0.85rem; + border-radius: 999px; + border: 1px solid rgba($indigo, 0.28); + background: transparent; + color: $body-color; + font-size: 0.86rem; + font-weight: 600; + cursor: pointer; +} + +.cil-end-vote button:hover { + border-color: $indigo; +} + +.cil-end-vote button[aria-pressed="true"] { + background: $indigo; + border-color: $indigo; + color: #fff; +} + +.cil-end-vote .thanks { + flex-basis: 100%; + font-size: 0.86rem; + color: lighten($body-color, 25%); +} + +.cil-end-progress { + display: flex; + align-items: center; + gap: 0.6rem; + font-size: 0.84rem; + color: lighten($body-color, 25%); +} + +.cil-end-progress .bar { + width: 110px; + height: 6px; + border-radius: 999px; + background: rgba($indigo, 0.12); + overflow: hidden; +} + +.cil-end-progress .bar i { + display: block; + height: 100%; + background: linear-gradient(90deg, $indigo, $lavender); + transition: width 0.4s ease; +} + +.cil-end .hub-next { + margin-top: 0.6rem; +} + +// 들어가며: 허브 배너 +a.hub-banner { + display: flex; + align-items: center; + gap: 1.1rem; + margin: 0.4rem 0 1.4rem; + padding: 1.1rem 1.3rem; + border-radius: 16px; + color: #fff; + text-decoration: none; + background: + radial-gradient(circle at 90% 10%, rgba($lavender, 0.5), transparent 50%), + linear-gradient(135deg, $navy 0%, $indigo 70%); + transition: transform 0.15s ease, box-shadow 0.15s ease; +} + +a.hub-banner:hover { + color: #fff; + transform: translateY(-2px); + box-shadow: 0 10px 26px rgba($navy, 0.25); +} + +.hub-banner img { + flex: none; + width: 52px; + height: auto; + margin: 0; +} + +.hub-banner-text { + display: flex; + flex-direction: column; + gap: 0.15rem; + min-width: 0; +} + +.hub-banner-k { + font-size: 0.76rem; + font-weight: 600; + opacity: 0.75; +} + +.hub-banner-t { + font-size: 1.25rem; + font-weight: 800; + letter-spacing: -0.01em; +} + +.hub-banner-d { + font-size: 0.88rem; + line-height: 1.6; + opacity: 0.88; +} + +.hub-banner-go { + flex: none; + margin-left: auto; + padding: 0.45rem 0.95rem; + border-radius: 999px; + background: #fff; + color: $navy; + font-size: 0.86rem; + font-weight: 700; + white-space: nowrap; +} + +.hub-banner-t { + line-height: 1.3; +} + +@media (max-width: 640px) { + a.hub-banner { + display: grid; + grid-template-columns: auto minmax(0, 1fr); + align-items: start; + gap: 0.8rem 0.9rem; + } + .hub-banner img { + width: 40px; + } + .hub-banner-go { + grid-column: 1 / -1; + justify-self: start; + margin-left: 0; + } +} + +// 장 끝: Causal Inference Hub에서 이어 볼 자료 +.hub-next { + margin: 2.6rem 0 0; + padding: 1.2rem 1.3rem 1.1rem; + border-radius: 14px; + border: 1px solid rgba($indigo, 0.18); + background: linear-gradient(135deg, $lavender-soft 0%, #fff 70%); +} + +.hub-next p { + margin: 0; +} + +.hub-next .hub-next-k { + display: flex; + align-items: center; + justify-content: flex-start; + gap: 0.45rem; + font-size: 0.78rem; + font-weight: 700; + color: $indigo; +} + +.hub-next .hub-next-k img { + display: block; + flex: none; + width: 18px; + height: auto; + margin: 0; +} + +.hub-next .hub-next-t { + margin-top: 0.45rem; + font-size: 1.12rem; + font-weight: 750; + color: $navy; +} + +.hub-next .hub-next-d { + margin-top: 0.25rem; + font-size: 0.92rem; + line-height: 1.65; +} + +.hub-next .hub-next-a { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + margin-top: 0.85rem; +} + +.hub-next .hub-next-a a { + display: inline-block; + padding: 0.4rem 0.95rem; + border-radius: 999px; + border: 1px solid rgba($indigo, 0.3); + font-size: 0.86rem; + font-weight: 650; + text-decoration: none; +} + +.hub-next .hub-next-a a.primary { + background: $indigo; + border-color: $indigo; + color: #fff; +} + +.hub-next .hub-next-a a:hover { + opacity: 0.88; +} + // 사이드바 상단: 가짜연구소 × 인과추론팀 .brand-lockup { display: flex; @@ -751,6 +1217,14 @@ h1.title .chapter-number { // 모바일 상단 경로: 부 이름은 숨기고 장 제목만 한 줄로 @media (max-width: 991.98px) { + .quarto-secondary-nav .container-fluid { + align-items: center; + } + .quarto-secondary-nav .quarto-page-breadcrumbs { + flex: 0 1 auto; + min-width: 0; + overflow: hidden; + } .quarto-secondary-nav .breadcrumb { flex-wrap: nowrap; overflow: hidden;