<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>resultofeffort</title>
    <link>https://resultofeffort.tistory.com/</link>
    <description>이건 첫 번째 레슨, 업무에서 마주친 문제 해결 경험 공유하기
이건 두 번째 레슨, 개인적으로 공부한 데이터/AI 지식을 기록하기
이건 세 번째 레슨, 다른 사람과 비교하지 말고 오직 어제의 나와 비교하기</description>
    <language>ko</language>
    <pubDate>Thu, 25 Jun 2026 19:54:30 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>ISFP의 블로그</managingEditor>
    <image>
      <title>resultofeffort</title>
      <url>https://tistory1.daumcdn.net/tistory/5265550/attach/9d98f8b6a454426e989780f51e6b438b</url>
      <link>https://resultofeffort.tistory.com</link>
    </image>
    <item>
      <title>[python] macOS에서 Apache Airflow 시작하기 (ETL 파이프라인 구축)</title>
      <link>https://resultofeffort.tistory.com/154</link>
      <description>&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1.Airflow 초기 설정&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;10&quot;&gt;Apache airflow는 Linux 기반이지만, macOS에서도 터미널을 통해 쉽게 설치하고 실행할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;11&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;11&quot;&gt;&lt;b&gt;1.1. 가상환경 생성(conda)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;11&quot;&gt;anaconda를 사용해서 python 3.10 버전의 가상환경을 생성 합니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# Anaconda를 사용하여 Python 3.10 환경을 생성
conda create -n airflow_lab python=3.10

# 가상환경 활성화
conda activate airflow_lab&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1.2. Airflow 설치&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Airflow 공식 문서에서는 pip 로 설치를 권장하기 때문에 Airflow와 MySQL Provider 패키지는 pip 로 설치 합니다.&lt;br /&gt;mysqlclient는 conda로 설치해주었습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1765499617783&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# Airflow 설치
pip install apache-airflow

# MySQL Provider 설치
pip install apache-airflow-providers-mysql

# [중요] MySQL Client 설치 (이거 안 하면 에러 남)
conda install -c conda-forge mysqlclient&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1.3. 환경 변수 설정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;macOS의 시스템 보안 정책으로 인해 Airflow가 갑작스럽게 종료되는 현상이 발생할 수 있습니다. 이를 방지하기 위해 다음 환경변수를 설정합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;⚠️ 주의: 이 설정은 현재 터미널에만 적용됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;해당 명령어는 현재 열려 있는 터미널 창을 닫으면 초기화됩니다. Airflow를 실행할 때마다 해당 명령어를 입력해 주어야 에러가 발생하지 않습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1765499617784&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# macOS 프록시 설정 (보안 정책 충돌 방지)
export no_proxy=&quot;*&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1.4. 서버 실행&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이제 Airflow 서버를 실행합니다. 실행 후 터미널에 표시되는 웹 주소(일반적으로 http://localhost:8080)로 접속하면 Airflow 대시보드를 확인할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1765499617784&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;airflow standalone&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot; data-path-to-node=&quot;6&quot;&gt;&lt;b&gt;2. Airflow 대시보드 접속하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;7&quot;&gt;&lt;b&gt;2.1.터미널에서 인증정보 확인하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;7&quot;&gt;airflow standalone 명령어를 실행하면 여러 로그가 빠르게 출력됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;7&quot;&gt;로그가 나타나타가 멈추는 순간, 위쪽을 잘 살펴보면 다음과 같은 박스를 찾을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;7&quot;&gt;터미널에 출력된 Password 문자열을 복사해야 합니다.&lt;/p&gt;
&lt;div&gt;
&lt;pre style=&quot;background-color: #f8f8f8; color: #383a42;&quot;&gt;&lt;code&gt;Standalone mode created: ...
User: admin
Password: [여기에_적힌_복잡한_문자열]  &amp;lt;-- 이걸 복사하세요!
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;※ 주의: 만약 로그에 비밀번호가 안 보인다면?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;Airflow 재실행 시에는 보안상 비밀번호가 로그에 뜨지 않습니다.&lt;br /&gt;이런 경우에는 새 터미널 창을 열어 아래 명령어중 하나를 실행하세요.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# 비밀번호 확인 명령어 (둘 중 하나 실행)
cat ~/airflow/standalone_admin_password.txt

# 또는 (Airflow 버전에 따라)
cat ~/airflow/simple_auth_manager_passwords.json.generated&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;admin:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;이 부분이 비밀번호 입니다.&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;857&quot; data-origin-height=&quot;72&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wQbru/dJMcahCVTZU/0DyGKVzIE1aULe9of2WtcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wQbru/dJMcahCVTZU/0DyGKVzIE1aULe9of2WtcK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wQbru/dJMcahCVTZU/0DyGKVzIE1aULe9of2WtcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwQbru%2FdJMcahCVTZU%2F0DyGKVzIE1aULe9of2WtcK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;857&quot; height=&quot;72&quot; data-origin-width=&quot;857&quot; data-origin-height=&quot;72&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;11&quot;&gt;&lt;b&gt;2.2.웹 브라우저에 접속하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;11&quot;&gt;웹 브라우저를(Chrome 등) 열고 주소창에 아래 주소를 입력합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1765499617785&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;http://localhost:8080&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;14&quot;&gt;&lt;b&gt;2.3.로그인 하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;14&quot;&gt;Airflow 로그인 화면이 표시되면 앞서 확인한 인증정보를 입력합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;14&quot;&gt;&lt;b&gt;- Username&lt;/b&gt;: admin 입력하시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;14&quot;&gt;&lt;b&gt;- Password&lt;/b&gt;: 위에서 복사한 비밀번호를 입력해줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;628&quot; data-origin-height=&quot;506&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kVYrv/dJMcacIo2RR/Tm8JCpywNeKG370xlROZiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kVYrv/dJMcacIo2RR/Tm8JCpywNeKG370xlROZiK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kVYrv/dJMcacIo2RR/Tm8JCpywNeKG370xlROZiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkVYrv%2FdJMcacIo2RR%2FTm8JCpywNeKG370xlROZiK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;387&quot; height=&quot;312&quot; data-origin-width=&quot;628&quot; data-origin-height=&quot;506&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;13&quot;&gt;로그인에 성공하면 Airflow 대시보드가 나타납니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2862&quot; data-origin-height=&quot;1364&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yGvtg/dJMcagKNCmC/AC2iHT1cNTTycPMXSaXCw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yGvtg/dJMcagKNCmC/AC2iHT1cNTTycPMXSaXCw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yGvtg/dJMcagKNCmC/AC2iHT1cNTTycPMXSaXCw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyGvtg%2FdJMcagKNCmC%2FAC2iHT1cNTTycPMXSaXCw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;673&quot; height=&quot;321&quot; data-origin-width=&quot;2862&quot; data-origin-height=&quot;1364&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot; data-path-to-node=&quot;9&quot;&gt;&lt;b&gt;3.실습용 데이터 생성하기&lt;/b&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;10&quot;&gt;Airflow와 연결하기 전에, Airflow가 가져올&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;실습용 데이터&lt;/b&gt;를 MySQL에 먼저 만들어 둬야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;10&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;11&quot;&gt;&lt;b&gt;3.1. MySQL 접속하기&lt;/b&gt;&lt;br /&gt;새로운 터미널 창을 열고 (command + n) 터미널에서 MySQL에 관리자 권한으로 접속합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;11&quot;&gt;(비밀번호가 있다면 입력 후 엔터, 비밀번호를 설정하신 적이 없다면 그냥 엔터!)&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;mysql -u root -p&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;558&quot; data-origin-height=&quot;219&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dGIxM5/dJMcadUM2cD/Ke7PRLWkrk3JK4HQ4RPyxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dGIxM5/dJMcadUM2cD/Ke7PRLWkrk3JK4HQ4RPyxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dGIxM5/dJMcadUM2cD/Ke7PRLWkrk3JK4HQ4RPyxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdGIxM5%2FdJMcadUM2cD%2FKe7PRLWkrk3JK4HQ4RPyxk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;558&quot; height=&quot;219&quot; data-origin-width=&quot;558&quot; data-origin-height=&quot;219&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;13&quot;&gt;&lt;b&gt;3.2. 데이터 생성 SQL 실행 (복사+붙여넣기)&lt;/b&gt;&lt;br /&gt;접속된 MySQL 화면(mysql&amp;gt;)에 아래 SQL 문을 통째로 복사해서 붙여넣으세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;13&quot;&gt;&lt;u&gt;game_log_db라는 데이터베이스&lt;/u&gt;를 만들고, 그 안에 가상의 유저 로그 3개를 넣는 명령어입니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;CREATE DATABASE IF NOT EXISTS game_log_db;
USE game_log_db;

CREATE TABLE IF NOT EXISTS access_log (
    user_id VARCHAR(50),
    event VARCHAR(50),
    created_at DATE
);

INSERT INTO access_log VALUES ('user_1', 'login', '2025-01-01');
INSERT INTO access_log VALUES ('user_2', 'logout', '2025-01-01');
INSERT INTO access_log VALUES ('user_3', 'level_up', '2025-01-01');

SELECT * FROM access_log;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;15&quot;&gt;&lt;b&gt;3.3. 확인 및 종료&lt;/b&gt;&lt;br /&gt;마지막에 SELECT 결과로 데이터 3줄이 잘 출력되었다면 성공입니다!&lt;br /&gt;exit를 입력해 MySQL을 빠져나옵니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;253&quot; data-origin-height=&quot;140&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bProlT/dJMcacIpkDN/X5RKNghQNOIOKK6A8hBMj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bProlT/dJMcacIpkDN/X5RKNghQNOIOKK6A8hBMj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bProlT/dJMcacIpkDN/X5RKNghQNOIOKK6A8hBMj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbProlT%2FdJMcacIpkDN%2FX5RKNghQNOIOKK6A8hBMj1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;334&quot; height=&quot;185&quot; data-origin-width=&quot;253&quot; data-origin-height=&quot;140&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot; data-path-to-node=&quot;13&quot;&gt;&lt;b&gt;4.Airflow - MySQL 커넥션 설정&lt;/b&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Airflow에서 MySQL 데이터베이스에 접근하려면 먼저 연결 설정을 등록해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Airflow 웹 대시보드의 '관리자' 메뉴에서 커넥션을 추가합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;경로&lt;span&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;좌측&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;탭&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;관리자&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;커넥션들&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;커넥션&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;추가&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;605&quot; data-origin-height=&quot;320&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9m9rM/dJMcadAueQY/tYZS4D0D00aR7gmeL8qr11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9m9rM/dJMcadAueQY/tYZS4D0D00aR7gmeL8qr11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9m9rM/dJMcadAueQY/tYZS4D0D00aR7gmeL8qr11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9m9rM%2FdJMcadAueQY%2FtYZS4D0D00aR7gmeL8qr11%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;605&quot; height=&quot;320&quot; data-origin-width=&quot;605&quot; data-origin-height=&quot;320&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot; data-path-to-node=&quot;14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;14&quot;&gt;&lt;b&gt;4.1.기본 정보 입력&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;14&quot;&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;커넥션ID&lt;/b&gt;: game_mysql_conn&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;14&quot;&gt;(Airflow 가 이 연결 설정을 부를 때 사용하는 고유한 식별자입니다. python 코드에서 이 이름으로 DB에 접속합니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;14&quot;&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;커넥션 유형&lt;/b&gt;: Mysql&lt;br /&gt;(데이터베이스 유형을 지정합니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot; data-path-to-node=&quot;14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;4&quot;&gt;&lt;b&gt;4.2.데이터베이스 연결 정보 입력&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;5&quot;&gt;맥북 로컬 환경에서 에러 없이 연결하려면 아래&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;4가지는 꼭 채워야 합니다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;5&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;5&quot;&gt;1.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Host&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(호스트): localhost&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(주의: 127.0.0.1로 쓰면 맥북 보안 설정 때문에 연결이 거부될 수 있습니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Login&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(로그인): root&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(MySQL 설치 시 기본 관리자 계정입니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Password&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(비밀번호): (본인 설정에 따라 다름)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(Mysqk울 설치할 때 비밀번호를 따로 설정 안 했다면 비워두세요.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Schema&lt;/b&gt;:&lt;span&gt;game_log_db&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;(앞서 생성한 데이터베이스 이름입니다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span&gt;4.3.Mac OS 호환성 설정&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(이걸 입력해야 TCP/IP 통신 오류를 우회하여 소켓으로 직통 연결됩니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot; data-path-to-node=&quot;4&quot;&gt;경로는 터미널에서 mysql -u root -&amp;gt; status로 확인하세요.)&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1765499617787&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;{&quot;socket&quot;: &quot;/tmp/mysql.sock&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;왜 이 설정(Mac OS 호환성 설정)이 필요한가?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;macOS에서 MySQL은 기본적으로 Unix Socket을 통해 통신합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;TCP/IP로 연결하려고 하면 &amp;lsquo;Connection Refused&amp;rsquo; 에러가 발생할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이 설정은 Airflow에게 소켓 통신 방식을 사용하도록 지시합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;MySQL&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;소켓&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;경로&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;확인하기&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;터미널에서&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;다음&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;명령어를&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;실행하여&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;정확한&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;경로를&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;확인하세요&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;pre style=&quot;background-color: #fafafa; color: #232425; text-align: start;&quot; data-source-line=&quot;104-107&quot;&gt;&lt;code&gt;Copymysql -u root
mysql&amp;gt; status
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;출력된 정보에서 'UNIX socket'으로 시작하는 라인을 찾으면, 소켓 파일의 경로를 확인할 수 있습니다 (보통 /tmp/mysql.sock).&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;만약&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;/var/run/mysqld/mysql.sock&lt;span&gt;이라면&lt;/span&gt;, Extra&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;필드를&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;그에&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;맞게&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;수정하면&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;됩니다&lt;/span&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;636&quot; data-origin-height=&quot;521&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OX1oI/dJMcabCINN0/3qFmm1ZZjara1oWUZhDKn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OX1oI/dJMcabCINN0/3qFmm1ZZjara1oWUZhDKn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OX1oI/dJMcabCINN0/3qFmm1ZZjara1oWUZhDKn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOX1oI%2FdJMcabCINN0%2F3qFmm1ZZjara1oWUZhDKn1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;636&quot; height=&quot;521&quot; data-origin-width=&quot;636&quot; data-origin-height=&quot;521&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;621&quot; data-origin-height=&quot;212&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cljPGf/dJMcahiDwQT/Zx5gVGuOYSPP9URk7K2XXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cljPGf/dJMcahiDwQT/Zx5gVGuOYSPP9URk7K2XXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cljPGf/dJMcahiDwQT/Zx5gVGuOYSPP9URk7K2XXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcljPGf%2FdJMcahiDwQT%2FZx5gVGuOYSPP9URk7K2XXk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;621&quot; height=&quot;212&quot; data-origin-width=&quot;621&quot; data-origin-height=&quot;212&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot; data-path-to-node=&quot;14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;14&quot;&gt;저장을 누르고 커넥션 목록 화면으로 돌아옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;14&quot;&gt;리스트에 game_mysql_conn이 추가된 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;106&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccU6Rc/dJMcacO99kr/1yf305lUkFQzkzzv85aW91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccU6Rc/dJMcacO99kr/1yf305lUkFQzkzzv85aW91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccU6Rc/dJMcacO99kr/1yf305lUkFQzkzzv85aW91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccU6Rc%2FdJMcacO99kr%2F1yf305lUkFQzkzzv85aW91%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;643&quot; height=&quot;77&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;106&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;이제&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Airflow&lt;span&gt;가&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;MySQL&lt;span&gt;에&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;접근할&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;수&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;있는&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;경로가&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;설정되었습니다&lt;/span&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;이&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;'game_mysql_conn'&lt;span&gt;이라는&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;연결&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;정보를&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;사용하여&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;다음&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;단계에서&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Python DAG&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;코드를&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;작성할&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;예정입니다&lt;/span&gt;.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot; data-path-to-node=&quot;16&quot;&gt;&lt;b&gt;5.DAG 파일 생성(ETL 구현)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Airflow와 MySQL 연결 설정이 끝났으니, 이제 실제로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;데이터를 추출(Extract)해서 파일로 저장(Load)하는 DAG&lt;/b&gt;를 작성해 봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;5&quot;&gt;&lt;b&gt;5.1. 데이터를 저장할 폴더 만들기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;6&quot;&gt;CSV 파일을 저장할 폴더가 없으면 에러가 발생할 수 있습니다. 터미널에서 미리 폴더를 생성해 줍니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre style=&quot;background-color: #f8f8f8; color: #383a42;&quot;&gt;&lt;code&gt;mkdir -p ~/airflow/data
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;8&quot;&gt;&lt;b&gt;5.2. DAG 파일 생성하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;8&quot;&gt;Airflow의 DAG 폴더 (~/airflow/dags/)에 Python 파일을 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;8&quot;&gt;이 DAG는 다음 기능을 수행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;8&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;8&quot;&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Extract&lt;/b&gt;: MySQL의 access_log 테이블에서 모든 데이터를 조회(SELECT)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;8&quot;&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Load&lt;/b&gt;: 조회된 데이터를 CSV 파일로 로컬 컴퓨터 저장&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;8&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;8&quot;&gt;다음 명령어를 터미널에 복사하여 실행하면 DAG 파일이 생성됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;10&quot;&gt;(터미널에 아래 내용을 그대로 복사+붙여넣기 하세요. 파일 생성과 내용 작성이 한 번에 됩니다!)&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;cat &amp;lt;&amp;lt;EOF &amp;gt; ~/airflow/dags/practice_connection.py
from airflow import DAG
from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
from airflow.operators.python import PythonOperator
from datetime import datetime
import csv

# ============================================
# 1단계: 데이터를 받아서 CSV 파일로 저장하는 함수 (Load)
# ============================================
def save_to_csv(**context):
    '''
    XCom(Airflow 우편함)에서 이전 Task가 조회한 데이터를 받아서
    CSV 파일로 저장합니다.
    '''
    # XCom에서 'read_db' Task의 결과 데이터를 꺼내옵니다
    data = context['ti'].xcom_pull(task_ids='read_db')
    
    # ⚠️ 중요: 아래 경로를 본인 사용자 이름에 맞게 수정하세요!
    # 예: /Users/[본인_사용자명]/airflow/data/game_log.csv
    file_path = '/Users/song/airflow/data/game_log.csv'
    
    # CSV 파일에 데이터를 쓰기 모드로 저장
    with open(file_path, 'w', newline='') as f:
        writer = csv.writer(f)
        writer.writerow(['user_id', 'event', 'date'])  # CSV 컬럼 제목
        for row in data:
            writer.writerow(row)  # 각 행의 데이터 입력
            
    print(f&quot;✅ 파일 저장 완료: {file_path}&quot;)

# ============================================
# 2단계: DAG(작업 흐름) 정의
# ============================================
with DAG(
    dag_id='mysql_to_csv_v1',        # Airflow 웹 대시보드에 보일 DAG 이름
    start_date=datetime(2025, 1, 1), # DAG 시작 날짜
    schedule='@daily',               # 매일 UTC 0시(한국시간 9시)에 자동 실행
    catchup=False                    # 과거 날짜의 미실행 작업을 실행하지 않음
) as dag:

    # [Task 1] MySQL 데이터베이스에서 데이터 조회하기 (Extract)
    read_db = SQLExecuteQueryOperator(
        task_id='read_db',                  # Task의 고유한 이름
        conn_id='game_mysql_conn',          # 아까 웹에서 설정한 MySQL 커넥션 ID
        sql=&quot;SELECT * FROM access_log;&quot;     # 실행할 SQL 쿼리
    )

    # [Task 2] 조회한 데이터를 파일로 변환하기 (Load)
    write_csv = PythonOperator(
        task_id='write_csv',                # Task의 고유한 이름
        python_callable=save_to_csv         # 실행할 Python 함수
    )

    # Task 의존성 설정: read_db를 먼저 실행 &amp;rarr; write_csv를 나중에 실행
    read_db &amp;gt;&amp;gt; write_csv
EOF&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot; data-path-to-node=&quot;3&quot;&gt;&lt;b&gt;6.실행 및 결과 확인 (Result)&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;407&quot; data-origin-height=&quot;93&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmSMac/dJMcahXfPFU/QiTepKpp9uac1UKHxrZ9gK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmSMac/dJMcahXfPFU/QiTepKpp9uac1UKHxrZ9gK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmSMac/dJMcahXfPFU/QiTepKpp9uac1UKHxrZ9gK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdmSMac%2FdJMcahXfPFU%2FQiTepKpp9uac1UKHxrZ9gK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;407&quot; height=&quot;93&quot; data-origin-width=&quot;407&quot; data-origin-height=&quot;93&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;4&quot;&gt;코드를 저장했다면 이제 Airflow 웹 화면에서 실행해 볼 차례입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot; data-path-to-node=&quot;4&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;5&quot;&gt;DAG 확인 및 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;5&quot;&gt;1. Airflow 웹 화면(localhost:8080)에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;[DAGs]&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;메뉴를 클릭하고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;새로고침(F5)&lt;/b&gt;을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;5&quot;&gt;2. 약 30초~1분 정도 기다리면 목록에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;mysql_to_csv_v1&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이 나타납니다.&lt;br /&gt;(만약 나오지 않는다면, Airflow 서버를 껐다 키신 후 진행해보세요)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;5&quot;&gt;3. 왼쪽의 토글 스위치(On/Off)를 켜서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;파란색(Unpaused)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;상태로 만듭니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;899&quot; data-origin-height=&quot;276&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Nq3aD/dJMcac2EPrz/mFcg2fwoKNtqIfRf8CW3aK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Nq3aD/dJMcac2EPrz/mFcg2fwoKNtqIfRf8CW3aK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Nq3aD/dJMcac2EPrz/mFcg2fwoKNtqIfRf8CW3aK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNq3aD%2FdJMcac2EPrz%2FmFcg2fwoKNtqIfRf8CW3aK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;899&quot; height=&quot;276&quot; data-origin-width=&quot;899&quot; data-origin-height=&quot;276&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;7&quot;&gt;4. 오른쪽의&amp;nbsp;&lt;b&gt;[▶] (Trigger DAG)&lt;/b&gt;&amp;nbsp;버튼을 눌러 작업을 실행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;7&quot;&gt;5. 성공 여부 확인 (Web UI)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;7&quot;&gt;read_db와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;write_csv&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;두 작업이 모두 진한 초록색(Success)으로 변하면 성공입니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;7&quot;&gt;(만약 빨간색(Failed)이 뜬다면, 클릭해서 [Log]를 확인해야 합니다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;721&quot; data-origin-height=&quot;96&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ef6qSt/dJMcaaw3bcw/lkXsjYSbrCJArImBCdHk11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ef6qSt/dJMcaaw3bcw/lkXsjYSbrCJArImBCdHk11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ef6qSt/dJMcaaw3bcw/lkXsjYSbrCJArImBCdHk11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fef6qSt%2FdJMcaaw3bcw%2FlkXsjYSbrCJArImBCdHk11%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;721&quot; height=&quot;96&quot; data-origin-width=&quot;721&quot; data-origin-height=&quot;96&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;814&quot; data-origin-height=&quot;136&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O7nUE/dJMcafSFbM6/wVsK4QBgKkpZkxjr46T8C0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O7nUE/dJMcafSFbM6/wVsK4QBgKkpZkxjr46T8C0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O7nUE/dJMcafSFbM6/wVsK4QBgKkpZkxjr46T8C0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO7nUE%2FdJMcafSFbM6%2FwVsK4QBgKkpZkxjr46T8C0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;724&quot; height=&quot;121&quot; data-origin-width=&quot;814&quot; data-origin-height=&quot;136&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;9&quot;&gt;6. 최종 결과물 확인 (CSV 파일)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot; data-path-to-node=&quot;10&quot;&gt;마지막으로 터미널에서 아래 명령어를 입력해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;진짜 파일이 생성되었는지&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;확인합니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# 파일 내용 출력하기
cat ~/airflow/data/game_log.csv&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot; data-path-to-node=&quot;12&quot;&gt;아래와 같이 MySQL에 들어있던 데이터가 콤마(,)로 구분된 텍스트 형태로 출력된다면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;ETL 파이프라인 구축 성공&lt;/b&gt;입니다!&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;503&quot; data-origin-height=&quot;80&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceRnqB/dJMcai9DFeB/7uzhFlI5dVZle7rqK77m61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceRnqB/dJMcai9DFeB/7uzhFlI5dVZle7rqK77m61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceRnqB/dJMcai9DFeB/7uzhFlI5dVZle7rqK77m61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceRnqB%2FdJMcai9DFeB%2F7uzhFlI5dVZle7rqK77m61%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;503&quot; height=&quot;80&quot; data-origin-width=&quot;503&quot; data-origin-height=&quot;80&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;br /&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>python</category>
      <author>ISFP의 블로그</author>
      <guid isPermaLink="true">https://resultofeffort.tistory.com/154</guid>
      <comments>https://resultofeffort.tistory.com/154#entry154comment</comments>
      <pubDate>Fri, 12 Dec 2025 09:38:14 +0900</pubDate>
    </item>
    <item>
      <title>[통계] 직관적 의사결정 vs 데이터 기반 의사결정</title>
      <link>https://resultofeffort.tistory.com/152</link>
      <description>&lt;pre id=&quot;code_1760083520465&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ㄹㄷㄹㄷㄹe

 문서 리스트
corpus = [
    &quot;나는 오늘 밥을 먹었다&quot;,
    &quot;밥을 먹고 운동을 했다&quot;,
    &quot;오늘 운동을 마치고 밥을 먹었다&quot;
]

# TF-IDF 벡터화
vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform(corpus)

# 코사인 유사도 계산
cosine_sim = cosine_similarity(tfidf_matrix, tfidf_matrix)

# 결과를 데이터프레임으로 보기 좋게 출력
df = pd.DataFrame(cosine_sim, index=[&quot;문서1&quot;, &quot;문서2&quot;, &quot;문서3&quot;], columns=[&quot;문서1&quot;, &quot;문서2&quot;, &quot;문서3&quot;])
print(&quot;코사인 유사도 행렬:&quot;)
print(df)
출처: https://resultofeffort.tistory.com/147 [resultofeffort:티스토리]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;두&amp;nbsp;가지&amp;nbsp;의사결정&amp;nbsp;방식의&amp;nbsp;이해&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 매일 수많은 의사결정을 내립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아침에 무엇을 입을지부터 저녁에는 무엇을 먹을지 말이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 선택을 할 때 우리가 사용하는 방식은 크게 두 가지로 나눌 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째는 &quot;직관적 의사결정&quot;입니다.&lt;br /&gt;이는 우리가 가장 많이 사용하는 방식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 제가 티셔츠를 판매하는 판매자라고 해볼게요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;판매하고자 하는 티셔츠의 색상을 선택해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 이 티셔츠를 최대한 많이 팔아야 하는 판매자이기 때문에 사람들이 가장 많이 구매할 것 같은 색상을 고를 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검정색이 가장 많이 판매가 될 것 같으니 100개를 발주하고 핑크색은 팔리지 않을 것 같아서 발주를 넣지 않을 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 결정이 바로 본인이 지금까지 쌓아온 경험과 직감으로 의사결정을 하는 방식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직관적 의사결정의 장점은 &quot;속도&quot;입니다. 데이터 수집이나 복잡한 분석 과정 없이도 빠르게 결정을 내릴 수 있기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 과정에서 데이터로 설명할 수 없는 아이디어나 접근 방법을 떠올리기도 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이러한 방법에는 단점이 있습니다. 의사결정자의 개인적인 편견이나 감정이 개입되기 때문에 같은 상황이라도 사람에 따라, 같은 사람이라도 기분에 따라 다른 결정을 내릴 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째는 &quot;데이터 기반 의사결정&quot;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 객관적인 수치와 분석 결과를 바탕으로 하는 결정을 내리는 방식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 넷플릭스에서 새로운 컨텐츠를 제작하려면 과거의 사람들이 가장 많이 소비한 컨텐츠의 종류와 분야, 시청자의 나이, 한달에 소비하는 시간을 고려해서 새로운 컨텐츠를 기획하고 생산하는 방식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 기반의 의사결정의 장점은 객관성과 재현성입니다. 동일한 데이터로 동일한 분석을 한다면 누가 분석하든 비슷한 결론에 도달할 수 있습니다. 또한 결정의 근거를 명확히 제시할 수 있어서 다른 사람들을 설득하기도 쉽습니다.&amp;nbsp; 하지만 이 방식도 단점이 존재합니다. 데이터를 분석하는데 수많은 리소스가 소요되고, 무엇보다 과거의 데이터를 기반으로 미래를 예측하는 것이기 때문에&amp;nbsp; 전혀 새로운 상황에서는 한계가 있을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;##&amp;nbsp; &amp;zwj; &amp;nbsp;데이터&amp;nbsp;사이언티스트가&amp;nbsp;갖춰야&amp;nbsp;할&amp;nbsp;역량&lt;br /&gt;&lt;br /&gt;그렇다면&amp;nbsp;데이터&amp;nbsp;기반&amp;nbsp;의사결정을&amp;nbsp;주도하는&amp;nbsp;데이터&amp;nbsp;사이언티스트는&amp;nbsp;어떤&amp;nbsp;능력을&amp;nbsp;갖춰야&amp;nbsp;할까요?&amp;nbsp;많은&amp;nbsp;사람들이&amp;nbsp;프로그래밍이나&amp;nbsp;통계학만&amp;nbsp;잘하면&amp;nbsp;된다고&amp;nbsp;생각하지만,&amp;nbsp;실제로는&amp;nbsp;훨씬&amp;nbsp;다양한&amp;nbsp;역량이&amp;nbsp;필요합니다.&lt;br /&gt;&lt;br /&gt;가장&amp;nbsp;기본이&amp;nbsp;되는&amp;nbsp;것은&amp;nbsp;당연히&amp;nbsp;기술적&amp;nbsp;역량입니다.&amp;nbsp;통계학의&amp;nbsp;기초&amp;nbsp;개념들을&amp;nbsp;이해하고,&amp;nbsp;Python이나&amp;nbsp;R&amp;nbsp;같은&amp;nbsp;프로그래밍&amp;nbsp;언어를&amp;nbsp;다룰&amp;nbsp;수&amp;nbsp;있어야&amp;nbsp;하죠.&amp;nbsp;SQL로&amp;nbsp;데이터베이스에서&amp;nbsp;필요한&amp;nbsp;데이터를&amp;nbsp;추출할&amp;nbsp;수&amp;nbsp;있어야&amp;nbsp;하고,&amp;nbsp;머신러닝&amp;nbsp;알고리즘들을&amp;nbsp;상황에&amp;nbsp;맞게&amp;nbsp;적용할&amp;nbsp;수&amp;nbsp;있어야&amp;nbsp;합니다.&amp;nbsp;하지만&amp;nbsp;이것만으로는&amp;nbsp;충분하지&amp;nbsp;않습니다.&lt;br /&gt;&lt;br /&gt;더&amp;nbsp;중요한&amp;nbsp;것은&amp;nbsp;분석적&amp;nbsp;사고력입니다.&amp;nbsp;복잡한&amp;nbsp;비즈니스&amp;nbsp;문제를&amp;nbsp;보았을&amp;nbsp;때&amp;nbsp;이것을&amp;nbsp;어떻게&amp;nbsp;데이터로&amp;nbsp;분석할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;형태로&amp;nbsp;바꿀&amp;nbsp;수&amp;nbsp;있는지&amp;nbsp;생각할&amp;nbsp;수&amp;nbsp;있어야&amp;nbsp;해요.&amp;nbsp;예를&amp;nbsp;들어&amp;nbsp;&quot;고객&amp;nbsp;만족도를&amp;nbsp;높이고&amp;nbsp;싶다&quot;는&amp;nbsp;막연한&amp;nbsp;요청을&amp;nbsp;받았을&amp;nbsp;때,&amp;nbsp;이를&amp;nbsp;&quot;고객&amp;nbsp;서비스&amp;nbsp;응답&amp;nbsp;시간과&amp;nbsp;만족도&amp;nbsp;점수&amp;nbsp;간의&amp;nbsp;관계&amp;nbsp;분석&quot;&amp;nbsp;같은&amp;nbsp;구체적인&amp;nbsp;분석&amp;nbsp;문제로&amp;nbsp;변환할&amp;nbsp;수&amp;nbsp;있어야&amp;nbsp;합니다.&lt;br /&gt;&lt;br /&gt;또한&amp;nbsp;비즈니스에&amp;nbsp;대한&amp;nbsp;이해도&amp;nbsp;필수입니다.&amp;nbsp;아무리&amp;nbsp;정교한&amp;nbsp;분석을&amp;nbsp;했더라도&amp;nbsp;그것이&amp;nbsp;실제&amp;nbsp;비즈니스에&amp;nbsp;어떤&amp;nbsp;의미가&amp;nbsp;있는지,&amp;nbsp;어떤&amp;nbsp;가치를&amp;nbsp;창출할&amp;nbsp;수&amp;nbsp;있는지&amp;nbsp;알지&amp;nbsp;못한다면&amp;nbsp;의미가&amp;nbsp;없거든요.&amp;nbsp;예를&amp;nbsp;들어&amp;nbsp;전자상거래&amp;nbsp;회사에서&amp;nbsp;일한다면&amp;nbsp;고객&amp;nbsp;획득&amp;nbsp;비용,&amp;nbsp;생애&amp;nbsp;가치,&amp;nbsp;전환율&amp;nbsp;같은&amp;nbsp;핵심&amp;nbsp;지표들을&amp;nbsp;이해하고&amp;nbsp;있어야&amp;nbsp;합니다.&lt;br /&gt;&lt;br /&gt;마지막으로,&amp;nbsp;많은&amp;nbsp;사람들이&amp;nbsp;간과하는&amp;nbsp;것이&amp;nbsp;커뮤니케이션&amp;nbsp;능력입니다.&amp;nbsp;데이터&amp;nbsp;분석&amp;nbsp;결과를&amp;nbsp;기술적&amp;nbsp;배경이&amp;nbsp;없는&amp;nbsp;경영진이나&amp;nbsp;동료들에게&amp;nbsp;이해하기&amp;nbsp;쉽게&amp;nbsp;설명할&amp;nbsp;수&amp;nbsp;있어야&amp;nbsp;해요.&amp;nbsp;복잡한&amp;nbsp;통계&amp;nbsp;분석&amp;nbsp;결과를&amp;nbsp;직관적인&amp;nbsp;시각화로&amp;nbsp;표현하고,&amp;nbsp;그것이&amp;nbsp;비즈니스에&amp;nbsp;미치는&amp;nbsp;영향을&amp;nbsp;스토리텔링으로&amp;nbsp;전달할&amp;nbsp;수&amp;nbsp;있어야&amp;nbsp;합니다.&lt;br /&gt;&lt;br /&gt;##&amp;nbsp; &amp;nbsp;통계적&amp;nbsp;의사결정&amp;nbsp;모형의&amp;nbsp;이해&lt;br /&gt;&lt;br /&gt;데이터&amp;nbsp;기반&amp;nbsp;의사결정을&amp;nbsp;체계적으로&amp;nbsp;수행하기&amp;nbsp;위해서는&amp;nbsp;일정한&amp;nbsp;프레임워크가&amp;nbsp;필요합니다.&amp;nbsp;가장&amp;nbsp;널리&amp;nbsp;사용되는&amp;nbsp;것&amp;nbsp;중&amp;nbsp;하나가&amp;nbsp;CRISP-DM&amp;nbsp;모형입니다.&amp;nbsp;이는&amp;nbsp;비즈니스&amp;nbsp;이해에서&amp;nbsp;시작해서&amp;nbsp;데이터&amp;nbsp;이해,&amp;nbsp;데이터&amp;nbsp;준비,&amp;nbsp;모델링,&amp;nbsp;평가,&amp;nbsp;배포까지의&amp;nbsp;순환적&amp;nbsp;과정을&amp;nbsp;제시합니다.&lt;br /&gt;&lt;br /&gt;예를&amp;nbsp;들어&amp;nbsp;온라인&amp;nbsp;쇼핑몰에서&amp;nbsp;고객&amp;nbsp;이탈을&amp;nbsp;예측하고&amp;nbsp;싶다고&amp;nbsp;해봅시다.&amp;nbsp;먼저&amp;nbsp;비즈니스&amp;nbsp;이해&amp;nbsp;단계에서는&amp;nbsp;왜&amp;nbsp;고객&amp;nbsp;이탈&amp;nbsp;예측이&amp;nbsp;중요한지,&amp;nbsp;어떤&amp;nbsp;비즈니스&amp;nbsp;가치를&amp;nbsp;창출할&amp;nbsp;수&amp;nbsp;있는지&amp;nbsp;명확히&amp;nbsp;해야&amp;nbsp;합니다.&amp;nbsp;데이터&amp;nbsp;이해&amp;nbsp;단계에서는&amp;nbsp;어떤&amp;nbsp;데이터가&amp;nbsp;있는지,&amp;nbsp;데이터의&amp;nbsp;품질은&amp;nbsp;어떤지&amp;nbsp;파악합니다.&amp;nbsp;데이터&amp;nbsp;준비&amp;nbsp;단계에서는&amp;nbsp;분석에&amp;nbsp;적합하도록&amp;nbsp;데이터를&amp;nbsp;정제하고&amp;nbsp;변환합니다.&amp;nbsp;모델링&amp;nbsp;단계에서는&amp;nbsp;적절한&amp;nbsp;머신러닝&amp;nbsp;알고리즘을&amp;nbsp;선택하고&amp;nbsp;모델을&amp;nbsp;구축합니다.&amp;nbsp;평가&amp;nbsp;단계에서는&amp;nbsp;모델의&amp;nbsp;성능을&amp;nbsp;검증하고,&amp;nbsp;마지막&amp;nbsp;배포&amp;nbsp;단계에서는&amp;nbsp;실제&amp;nbsp;업무에&amp;nbsp;적용합니다.&lt;br /&gt;&lt;br /&gt;또&amp;nbsp;다른&amp;nbsp;중요한&amp;nbsp;프레임워크는&amp;nbsp;통계적&amp;nbsp;가설검정입니다.&amp;nbsp;이는&amp;nbsp;특정&amp;nbsp;주장이나&amp;nbsp;가설이&amp;nbsp;통계적으로&amp;nbsp;의미가&amp;nbsp;있는지&amp;nbsp;객관적으로&amp;nbsp;판단하는&amp;nbsp;방법입니다.&amp;nbsp;예를&amp;nbsp;들어&amp;nbsp;새로운&amp;nbsp;웹사이트&amp;nbsp;디자인이&amp;nbsp;기존&amp;nbsp;디자인보다&amp;nbsp;전환율을&amp;nbsp;높인다고&amp;nbsp;주장할&amp;nbsp;때,&amp;nbsp;이를&amp;nbsp;단순히&amp;nbsp;&quot;느낌상&amp;nbsp;좋아&amp;nbsp;보인다&quot;가&amp;nbsp;아니라&amp;nbsp;통계적으로&amp;nbsp;검증할&amp;nbsp;수&amp;nbsp;있어야&amp;nbsp;합니다.&lt;br /&gt;&lt;br /&gt;##&amp;nbsp; &amp;nbsp;실무에서의&amp;nbsp;균형잡힌&amp;nbsp;접근&lt;br /&gt;&lt;br /&gt;하지만&amp;nbsp;실제&amp;nbsp;업무에서는&amp;nbsp;데이터와&amp;nbsp;직관을&amp;nbsp;완전히&amp;nbsp;분리해서&amp;nbsp;생각할&amp;nbsp;수&amp;nbsp;없습니다.&amp;nbsp;가장&amp;nbsp;효과적인&amp;nbsp;의사결정은&amp;nbsp;두&amp;nbsp;방식을&amp;nbsp;적절히&amp;nbsp;조합할&amp;nbsp;때&amp;nbsp;나옵니다.&amp;nbsp;직관으로&amp;nbsp;가설을&amp;nbsp;세우고&amp;nbsp;데이터로&amp;nbsp;검증하거나,&amp;nbsp;데이터&amp;nbsp;분석&amp;nbsp;결과를&amp;nbsp;직관과&amp;nbsp;경험으로&amp;nbsp;해석하는&amp;nbsp;것이죠.&lt;br /&gt;&lt;br /&gt;예를&amp;nbsp;들어,&amp;nbsp;데이터&amp;nbsp;분석&amp;nbsp;결과&amp;nbsp;특정&amp;nbsp;고객&amp;nbsp;그룹의&amp;nbsp;구매율이&amp;nbsp;급격히&amp;nbsp;떨어졌다고&amp;nbsp;나타났다면,&amp;nbsp;이것만으로는&amp;nbsp;원인을&amp;nbsp;알&amp;nbsp;수&amp;nbsp;없습니다.&amp;nbsp;이때&amp;nbsp;현장&amp;nbsp;경험이&amp;nbsp;풍부한&amp;nbsp;마케팅&amp;nbsp;담당자의&amp;nbsp;직관이&amp;nbsp;&quot;아,&amp;nbsp;최근에&amp;nbsp;경쟁사가&amp;nbsp;대대적인&amp;nbsp;할인&amp;nbsp;이벤트를&amp;nbsp;했었지&quot;라는&amp;nbsp;통찰을&amp;nbsp;제공할&amp;nbsp;수&amp;nbsp;있어요.&amp;nbsp;반대로&amp;nbsp;&quot;고객들이&amp;nbsp;모바일&amp;nbsp;앱을&amp;nbsp;더&amp;nbsp;선호할&amp;nbsp;것&amp;nbsp;같다&quot;는&amp;nbsp;직관적&amp;nbsp;가설을&amp;nbsp;세웠다면,&amp;nbsp;이를&amp;nbsp;A/B&amp;nbsp;테스트나&amp;nbsp;사용자&amp;nbsp;행동&amp;nbsp;데이터&amp;nbsp;분석으로&amp;nbsp;검증할&amp;nbsp;수&amp;nbsp;있습니다.&lt;br /&gt;&lt;br /&gt;결국&amp;nbsp;이&amp;nbsp;섹션에서&amp;nbsp;가장&amp;nbsp;중요한&amp;nbsp;것은&amp;nbsp;데이터&amp;nbsp;분석의&amp;nbsp;가치를&amp;nbsp;이해하는&amp;nbsp;것입니다.&amp;nbsp;데이터&amp;nbsp;기반&amp;nbsp;의사결정이&amp;nbsp;만능은&amp;nbsp;아니지만,&amp;nbsp;객관성과&amp;nbsp;재현성,&amp;nbsp;그리고&amp;nbsp;예측&amp;nbsp;가능성이라는&amp;nbsp;강력한&amp;nbsp;장점을&amp;nbsp;가지고&amp;nbsp;있다는&amp;nbsp;점을&amp;nbsp;알아야&amp;nbsp;합니다.&amp;nbsp;동시에&amp;nbsp;데이터&amp;nbsp;사이언티스트로서&amp;nbsp;성공하기&amp;nbsp;위해서는&amp;nbsp;기술적&amp;nbsp;역량뿐만&amp;nbsp;아니라&amp;nbsp;비즈니스&amp;nbsp;이해력과&amp;nbsp;커뮤니케이션&amp;nbsp;능력까지&amp;nbsp;갖춰야&amp;nbsp;한다는&amp;nbsp;점도&amp;nbsp;기억해두세요.&lt;/p&gt;</description>
      <author>ISFP의 블로그</author>
      <guid isPermaLink="true">https://resultofeffort.tistory.com/152</guid>
      <comments>https://resultofeffort.tistory.com/152#entry152comment</comments>
      <pubDate>Tue, 30 Sep 2025 18:23:05 +0900</pubDate>
    </item>
    <item>
      <title>[오류Error] RateLimitError: Error code: 429 - {'error': {'message': 'You exceeded your current quota, please check your plan and billing details. For more information on this error, read the docs: https://platform.openai.com/docs/guides/error-codes/api-erro</title>
      <link>https://resultofeffort.tistory.com/151</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;OpenAI API를 호출하려고 보니 갑자기 다음과 같은 에러가 떴습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;gt; &amp;ldquo;You exceeded your current quota, please check your plan and billing details. For more information on this error, read the docs: &lt;a href=&quot;https://platform.openai.com/docs/guides/error-codes/api-errors.&quot;&gt;https://platform.openai.com/docs/guides/error-codes/api-errors.&lt;/a&gt;&amp;rdquo; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;[오류] RateLimitError: 429 &amp;ndash; 현재 할당량을 초과했습니다. 요금제 및 결제 정보를 확인해 주세요.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;&lt;b&gt;&lt;a href=&quot;https://platform.openai.com/docs/guides/error-codes/api-errors.&quot;&gt;https://platform.openai.com/docs/guides/error-codes/api-errors.&lt;/a&gt;&quot; 사이트에 접속하여&lt;/b&gt;&lt;br /&gt;에러 설명(429)을 살펴보니 &lt;b&gt;&amp;ldquo;API 월간 사용량 한도에 도달했거나, 선불 크레딧을 모두 사용했음을 나타냅니다.&amp;rdquo; 라고 적혀있었다.&amp;nbsp;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;707&quot; data-origin-height=&quot;428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2pHaM/btsOu4zg47U/1FyS8D6IksldAICSq4DTS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2pHaM/btsOu4zg47U/1FyS8D6IksldAICSq4DTS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2pHaM/btsOu4zg47U/1FyS8D6IksldAICSq4DTS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2pHaM%2FbtsOu4zg47U%2F1FyS8D6IksldAICSq4DTS0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;707&quot; height=&quot;428&quot; data-origin-width=&quot;707&quot; data-origin-height=&quot;428&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 난 현재 유료 계정을 사용 중이고 과도한 API 호출을 하지 않았는데도이런 에러가 발생했어서 .. 이유를 찾는데 좀 헤매다가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확인해보니 &amp;nbsp;&lt;b&gt;결제 수단(신용카드)이 등록되어 있지 않아 Auto-recharge가 작동하지 않았기 때문&lt;/b&gt;이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론적으로&amp;nbsp;Payment methods에 카드 등록을 해주니 해결이 되었음.&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. OpenAI Console &amp;rarr; Billing &amp;rarr; Payment methods &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2388&quot; data-origin-height=&quot;1172&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b94fgI/btsOt8bsdqg/FU1kRAXYNOvxWF5KKO4JU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b94fgI/btsOt8bsdqg/FU1kRAXYNOvxWF5KKO4JU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b94fgI/btsOt8bsdqg/FU1kRAXYNOvxWF5KKO4JU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb94fgI%2FbtsOt8bsdqg%2FFU1kRAXYNOvxWF5KKO4JU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2388&quot; height=&quot;1172&quot; data-origin-width=&quot;2388&quot; data-origin-height=&quot;1172&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;2.&lt;/span&gt; Auto-recharge 설정 확인&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp; &lt;/span&gt;- Billing &amp;rarr; Overview &amp;rarr; Auto-recharge가 On 상태인지 확인 &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp; &lt;/span&gt;- (최소 잔액 $&lt;span&gt;5&lt;/span&gt; 이하 시, 자동으로 $&lt;span&gt;100&lt;/span&gt; 충전) &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;카드등록 해두니 자동으로 충전이 잘 된다..!&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2836&quot; data-origin-height=&quot;1382&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwjL20/btsOuQnLtQi/KNRREUnMLMSPt9KWtwhAF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwjL20/btsOuQnLtQi/KNRREUnMLMSPt9KWtwhAF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwjL20/btsOuQnLtQi/KNRREUnMLMSPt9KWtwhAF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwjL20%2FbtsOuQnLtQi%2FKNRREUnMLMSPt9KWtwhAF1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2836&quot; height=&quot;1382&quot; data-origin-width=&quot;2836&quot; data-origin-height=&quot;1382&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;3.&lt;/span&gt; API 호출 재실행&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>오류Error</category>
      <category>AI개발</category>
      <category>API</category>
      <category>api오류</category>
      <category>autorecharge</category>
      <category>openai</category>
      <category>Python</category>
      <category>ratelimiterror</category>
      <category>결제관리</category>
      <category>트러블슈팅</category>
      <category>할당량초과</category>
      <author>ISFP의 블로그</author>
      <guid isPermaLink="true">https://resultofeffort.tistory.com/151</guid>
      <comments>https://resultofeffort.tistory.com/151#entry151comment</comments>
      <pubDate>Tue, 10 Jun 2025 14:09:35 +0900</pubDate>
    </item>
    <item>
      <title>[오류Error] Failed to start project studioError invoking remote method 'up': Error: Docker not installed or not running: ExecaError: Command failed with exit code 1: which docker</title>
      <link>https://resultofeffort.tistory.com/150</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;LangGraph를 공부하던 중 Agentic Application을 만들기 위한 IDE인 LangGraph Studio라는 서비스를 알게 되었습니다. 이 도구가 AI 에이전트 개발을 시각적으로 도와준다고 하여 설치해보기로 했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;%EC%84%A4%EC%B9%98-%EA%B3%BC%EC%A0%95&quot; style=&quot;list-style-type: none; background-color: #ffffff; color: #232425; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;설치 과정&lt;/h2&gt;
&lt;p style=&quot;list-style-type: none; background-color: #ffffff; color: #232425; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;LangGraph Studio는 현재 맥북에서만 지원되는 것 같습니다. 공식 사이트에서 dmg 파일을 다운로드하여 설치했습니다.&lt;/p&gt;
&lt;p style=&quot;list-style-type: none; background-color: #ffffff; color: #232425; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;%EC%B2%AB-%EB%B2%88%EC%A7%B8-%EC%98%A4%EB%A5%98%3A-docker-%EA%B4%80%EB%A0%A8-%EB%AC%B8%EC%A0%9C&quot; style=&quot;list-style-type: none; background-color: #ffffff; color: #232425; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;첫 번째 오류: Docker 관련 문제&lt;/h2&gt;
&lt;p style=&quot;list-style-type: none; background-color: #ffffff; color: #232425; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;설치 후 실행했더니 다음과 같은 오류가 발생했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;235&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bf3Zhd/btsNoZ7Kpi1/MYtoKj33ddJkooEX18H8vK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bf3Zhd/btsNoZ7Kpi1/MYtoKj33ddJkooEX18H8vK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bf3Zhd/btsNoZ7Kpi1/MYtoKj33ddJkooEX18H8vK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbf3Zhd%2FbtsNoZ7Kpi1%2FMYtoKj33ddJkooEX18H8vK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;602&quot; height=&quot;235&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;235&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1744967150936&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Failed to start project studio
Error invoking remote method 'up': Error: Docker not installed or not running: ExecaError: Command failed with exit code 1: which docker&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;(도커가 필요한 줄 몰랐다.. 그래서 바로 Docker 를 설치해주었다.)&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;list-style-type: none; background-color: #ffffff; color: #232425; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;해결 방법&lt;/h3&gt;
&lt;figure id=&quot;og_1744967889598&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Docker Desktop: The #1 Containerization Tool for Developers | Docker&quot; data-og-description=&quot;Docker Desktop is collaborative containerization software for developers. Get started and download Docker Desktop today on Mac, Windows, or Linux.&quot; data-og-host=&quot;www.docker.com&quot; data-og-source-url=&quot;https://www.docker.com/products/docker-desktop/&quot; data-og-url=&quot;https://www.docker.com/products/docker-desktop/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dEfGAM/hyYFzCcSmM/b0tjK3ShYlyB8usdKzb9SK/img.png?width=1110&amp;amp;height=580&amp;amp;face=0_0_1110_580,https://scrap.kakaocdn.net/dn/b5pN7I/hyYIcM7jrq/aQMRKGkDqkyvW1O1FGtkD1/img.png?width=1110&amp;amp;height=580&amp;amp;face=0_0_1110_580&quot;&gt;&lt;a href=&quot;https://www.docker.com/products/docker-desktop/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.docker.com/products/docker-desktop/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dEfGAM/hyYFzCcSmM/b0tjK3ShYlyB8usdKzb9SK/img.png?width=1110&amp;amp;height=580&amp;amp;face=0_0_1110_580,https://scrap.kakaocdn.net/dn/b5pN7I/hyYIcM7jrq/aQMRKGkDqkyvW1O1FGtkD1/img.png?width=1110&amp;amp;height=580&amp;amp;face=0_0_1110_580');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Docker Desktop: The #1 Containerization Tool for Developers | Docker&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Docker Desktop is collaborative containerization software for developers. Get started and download Docker Desktop today on Mac, Windows, or Linux.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.docker.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #232425; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot;&gt;&lt;b&gt;Docker 설치 확인하기&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Docker가 설치되어 있지 않다면,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://www.docker.com/products/docker-desktop/&quot;&gt;Docker 공식 사이트&lt;/a&gt;에서 운영체제에 맞는 Docker Desktop을 다운로드하여 설치한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot;&gt;&lt;b&gt;Docker 실행 확인하기&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Docker Desktop을 실행하고, 상태 표시기(시스템 트레이/메뉴바)에서 Docker가 실행 중인지 확인한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot;&gt;&lt;b&gt;Docker 버전 확인하기&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;LangGraph Studio는 Docker Compose 버전 2.22.0 이상을 요구합니다. 터미널에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;docker-compose --version&lt;span&gt;&amp;nbsp;&lt;/span&gt;명령으로 버전을 확인하고, 필요시 업데이트한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 style=&quot;list-style-type: none; background-color: #ffffff; color: #232425; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 id=&quot;%EB%91%90-%EB%B2%88%EC%A7%B8-%EC%98%A4%EB%A5%98%3A-.env-%ED%8C%8C%EC%9D%BC-%EB%AC%B8%EC%A0%9C&quot; style=&quot;list-style-type: none; background-color: #ffffff; color: #232425; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;두 번째 오류: .env 파일 문제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;Docker를 설치하고 실행한 후 LangGraph Studio를 다시 시작했더니 오류 메시지가 바뀌었다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;565&quot; data-origin-height=&quot;201&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9LdKX/btsNq0ySK88/GNGiG3NtxK3UlGRfuYezqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9LdKX/btsNq0ySK88/GNGiG3NtxK3UlGRfuYezqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9LdKX/btsNq0ySK88/GNGiG3NtxK3UlGRfuYezqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9LdKX%2FbtsNq0ySK88%2FGNGiG3NtxK3UlGRfuYezqk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;565&quot; height=&quot;201&quot; data-origin-width=&quot;565&quot; data-origin-height=&quot;201&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1744967433634&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Failed to start project studio
Error invoking remote method 'up': Error: Could not read env file: /Users/path/to/project/studio/.env&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;LangGraph Studio가 API 키와 같은 환경 변수를 담고 있는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;.env&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;파일을 찾을 수 없어서 발생한 문제였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95-1&quot; style=&quot;list-style-type: none; background-color: #ffffff; color: #232425; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;해결 방법&lt;/h3&gt;
&lt;p style=&quot;list-style-type: none; background-color: #ffffff; color: #232425; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다행히 제가 사용하려던 프로젝트 폴더에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;.env.example&lt;span&gt;&amp;nbsp;&lt;/span&gt;파일이 이미 존재했습니다. 이 파일은 필요한 환경 변수의 템플릿 역할을 합니다.&lt;/p&gt;
&lt;p style=&quot;list-style-type: none; background-color: #ffffff; color: #232425; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. .env.example&lt;span&gt;&amp;nbsp;&lt;/span&gt;파일을&lt;span&gt;&amp;nbsp;&lt;/span&gt;.env&lt;span&gt;&amp;nbsp;&lt;/span&gt;파일로 복사해주었습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744968012024&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cp /path/to/project/studio/.env.example /path/to/project/studio/.env&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.&amp;nbsp;텍스트 에디터로&lt;span&gt;&amp;nbsp;&lt;/span&gt;.env&lt;span&gt;&amp;nbsp;&lt;/span&gt;파일을 열고 OpenAI API 키를 입력했습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1744968033050&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;OPENAI_API_KEY=sk-my_api_key_here&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LangGraph Studio를 재시작했더니 드디어 정상적으로 로드 성공!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1916&quot; data-origin-height=&quot;965&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HlXqT/btsNrgBufSo/TY7DgnH3UmpZNMUS2vCjd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HlXqT/btsNrgBufSo/TY7DgnH3UmpZNMUS2vCjd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HlXqT/btsNrgBufSo/TY7DgnH3UmpZNMUS2vCjd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHlXqT%2FbtsNrgBufSo%2FTY7DgnH3UmpZNMUS2vCjd0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1916&quot; height=&quot;965&quot; data-origin-width=&quot;1916&quot; data-origin-height=&quot;965&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>오류Error</category>
      <category>Docker</category>
      <category>error</category>
      <category>langgraph</category>
      <category>langgraph studio</category>
      <category>해결</category>
      <author>ISFP의 블로그</author>
      <guid isPermaLink="true">https://resultofeffort.tistory.com/150</guid>
      <comments>https://resultofeffort.tistory.com/150#entry150comment</comments>
      <pubDate>Fri, 18 Apr 2025 18:21:55 +0900</pubDate>
    </item>
    <item>
      <title>[오류Error] VS Code Remote-SSH: &amp;quot;원격 호스트가 VS Code Server를 실행하기 위한 필수 구성 요소를 충족하지 않습니다&amp;quot; 오류 해결 후기</title>
      <link>https://resultofeffort.tistory.com/149</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;could&amp;nbsp;not&amp;nbsp;establish&amp;nbsp;connection&amp;nbsp;to&amp;nbsp;&quot;서버ip&quot;:&amp;nbsp;the&amp;nbsp;remote&amp;nbsp;host&amp;nbsp;does&amp;nbsp;not&amp;nbsp;meet&amp;nbsp;the&amp;nbsp;prerequisites&amp;nbsp;for&amp;nbsp;running&amp;nbsp;vs&amp;nbsp;code&amp;nbsp;server.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;s&gt;2시간 30분 삽질 완료^^&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;s&gt;그래도 해결했으니 진짜 다행...........&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제 상황&lt;/b&gt;&lt;/h2&gt;
&lt;p data-end=&quot;501&quot; data-start=&quot;408&quot; data-ke-size=&quot;size18&quot;&gt;오늘 출근해서 VS Code에서 Remote - SSH 기능을 사용하려고 했는데,&lt;br /&gt;SSH로는 접속이 잘 되는데도 불구하고 아래와 같은 에러 메시지가 반복적으로 발생하였음.&lt;/p&gt;
&lt;p data-end=&quot;501&quot; data-start=&quot;408&quot; data-ke-size=&quot;size18&quot;&gt;(분명 어제까지는 멀쩡하게 접속이 되었단 말이지.ㅠㅠㅠ)&lt;/p&gt;
&lt;pre class=&quot;1c&quot;&gt;&lt;code&gt;&quot;원격 호스트가 VS Code Server를 실행하기 위한 필수 구성 요소를 충족하지 않습니다.&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;나의 환경&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;로컬 OS: macOS Sonoma 14.4.1 (Darwin x64 23.5.0, Apple Silicon)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;로컬 VS Code 버전: 1.99.2 (최신 버전)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;서버&lt;/span&gt; OS: Ubuntu 18.04 LTS (glibc: 2.27 / Node.js: v14.16.0)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;시도했던 해결 방법들 (실패)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;/etc/hosts 정리&lt;/li&gt;
&lt;li&gt;환경 변수 / 프록시 확인&lt;/li&gt;
&lt;li&gt;.zshrc / .bashrc 초기화&lt;/li&gt;
&lt;li&gt;known_hosts 삭제&lt;/li&gt;
&lt;li&gt;VS Code 초기화 &amp;amp; 재설치&lt;/li&gt;
&lt;li&gt;settings.json 수동 생성&lt;/li&gt;
&lt;li&gt;Remote-SSH 확장 재설치&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;rarr; &lt;b&gt;모두 실패.&lt;/b&gt;&lt;br /&gt;&lt;b&gt;원인은 glibc 2.27 환경에서 VS Code 최신 버전이 원격 서버 환경을 차단하기 때문.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;최종 해결 방법&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;결론부터 말하자면, &quot;VS Code 버전 다운그레이드 + 자동 업데이트 비활성화&quot;가 답이었습니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;해결 순서 정리&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. VS Code 1.85.1 버전 설치 (기존에 설치 되어있는 Vs Code는 제거해주었음)&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;# 기존 VS Code 삭제
sudo rm -rf /Applications/Visual\ Studio\ Code.app
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a title=&quot;https://code.visualstudio.com/updates/v1_85&quot; href=&quot;https://code.visualstudio.com/updates/v1_85&quot;&gt;  다운로드 링크 (VS Code 1.85.1)&lt;/a&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 업데이트 모드 끄기 (처음에 이거 안했더니 자동 업데이트 되서 다시 설치함^^)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;VS Code 실행 &amp;rarr; Cmd + , &amp;rarr; &quot;업데이트&quot; 검색 &amp;rarr; &lt;b&gt;응용 프로그램 &amp;gt; 업데이트 모드: &quot;none&quot;&lt;/b&gt; 으로 설정&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;583&quot; data-origin-height=&quot;272&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bs7i0f/btsNh74t65F/2qy9uDkg4nLKX54bCqYpa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bs7i0f/btsNh74t65F/2qy9uDkg4nLKX54bCqYpa1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bs7i0f/btsNh74t65F/2qy9uDkg4nLKX54bCqYpa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbs7i0f%2FbtsNh74t65F%2F2qy9uDkg4nLKX54bCqYpa1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;583&quot; height=&quot;272&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;583&quot; data-origin-height=&quot;272&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 확장 프로그램에서 Remote - SSH 를 제거 후 다시 설치&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 서버 접속 완료&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;참고&lt;/b&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1744340712023&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;The remote host may not meet vs code server's prerequisites for glibc and libstdc++ vscod&quot; data-og-description=&quot;I was working on the host server. Everything was great till yesterday and today when I start my server, suddenly error occurs in VS code. And my server is not connecting anymore. What should I do? ...&quot; data-og-host=&quot;stackoverflow.com&quot; data-og-source-url=&quot;https://stackoverflow.com/questions/69626028/the-remote-host-may-not-meet-vs-code-servers-prerequisites-for-glibc-and-libstd&quot; data-og-url=&quot;https://stackoverflow.com/questions/69626028/the-remote-host-may-not-meet-vs-code-servers-prerequisites-for-glibc-and-libstd&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/exIS7/hyYCbbadOz/QliSDw8BCJnDwGm3k3eRDK/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316,https://scrap.kakaocdn.net/dn/fzUoS/hyYEzPr4rm/wT4UJtKyoxvslkTVWTIVuk/img.png?width=514&amp;amp;height=630&amp;amp;face=0_0_514_630,https://scrap.kakaocdn.net/dn/ibHlR/hyYEAU88GM/bmmOhTbDXkCrpX7KJksPk1/img.png?width=1482&amp;amp;height=200&amp;amp;face=0_0_1482_200&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/69626028/the-remote-host-may-not-meet-vs-code-servers-prerequisites-for-glibc-and-libstd&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://stackoverflow.com/questions/69626028/the-remote-host-may-not-meet-vs-code-servers-prerequisites-for-glibc-and-libstd&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/exIS7/hyYCbbadOz/QliSDw8BCJnDwGm3k3eRDK/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316,https://scrap.kakaocdn.net/dn/fzUoS/hyYEzPr4rm/wT4UJtKyoxvslkTVWTIVuk/img.png?width=514&amp;amp;height=630&amp;amp;face=0_0_514_630,https://scrap.kakaocdn.net/dn/ibHlR/hyYEAU88GM/bmmOhTbDXkCrpX7KJksPk1/img.png?width=1482&amp;amp;height=200&amp;amp;face=0_0_1482_200');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;The remote host may not meet vs code server's prerequisites for glibc and libstdc++ vscod&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;I was working on the host server. Everything was great till yesterday and today when I start my server, suddenly error occurs in VS code. And my server is not connecting anymore. What should I do? ...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;stackoverflow.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1744340736574&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;The remote host may not meet VS Code Server's prerequisites for glibc and libstdc++ &amp;middot; Issue #9501 &amp;middot; microsoft/vscode-remote-re&quot; data-og-description=&quot;There was no problem with remote SSH until 3 days ago. Now I'm getting the following error and I can't connect to the server The remote host may not meet VS Code Server's prerequisites for glibc an...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/microsoft/vscode-remote-release/issues/9501&quot; data-og-url=&quot;https://github.com/microsoft/vscode-remote-release/issues/9501&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/wD213/hyYCcnyoYb/3r00jA2kRfG3E1qWxqdKrk/img.png?width=1200&amp;amp;height=600&amp;amp;face=967_121_1049_211,https://scrap.kakaocdn.net/dn/Blvw5/hyYCgjcG96/5kWCOKFaFo5kfdQcoxlhM0/img.png?width=1200&amp;amp;height=600&amp;amp;face=967_121_1049_211&quot;&gt;&lt;a href=&quot;https://github.com/microsoft/vscode-remote-release/issues/9501&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/microsoft/vscode-remote-release/issues/9501&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/wD213/hyYCcnyoYb/3r00jA2kRfG3E1qWxqdKrk/img.png?width=1200&amp;amp;height=600&amp;amp;face=967_121_1049_211,https://scrap.kakaocdn.net/dn/Blvw5/hyYCgjcG96/5kWCOKFaFo5kfdQcoxlhM0/img.png?width=1200&amp;amp;height=600&amp;amp;face=967_121_1049_211');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;The remote host may not meet VS Code Server's prerequisites for glibc and libstdc++ &amp;middot; Issue #9501 &amp;middot; microsoft/vscode-remote-re&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;There was no problem with remote SSH until 3 days ago. Now I'm getting the following error and I can't connect to the server The remote host may not meet VS Code Server's prerequisites for glibc an...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>오류Error</category>
      <category>glibc</category>
      <category>SSH</category>
      <category>vsode</category>
      <author>ISFP의 블로그</author>
      <guid isPermaLink="true">https://resultofeffort.tistory.com/149</guid>
      <comments>https://resultofeffort.tistory.com/149#entry149comment</comments>
      <pubDate>Fri, 11 Apr 2025 11:55:49 +0900</pubDate>
    </item>
    <item>
      <title>[pytorch] 시퀀스-투-시퀀스(seq2seq)</title>
      <link>https://resultofeffort.tistory.com/148</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;seq2seq의 기본 구조와 작동 원리&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Sequence-to-Sequence(seq2seq) 모델은&amp;nbsp;&lt;b&gt;한 시퀀스&lt;/b&gt;를&amp;nbsp;&lt;b&gt;다른 시퀀스로 변환&lt;/b&gt;하는 신경망 모델입니다.&lt;br /&gt;예를 들어, &quot;안녕하세요&quot;라는 한국어 문장을 &quot;Hello&quot;라는 영어 문장으로 번역하는 것처럼, 입력 시퀀스를 받아서 다른 형태의 출력 시퀀스를 생성합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;인코더(Encoder)-디코더(Decoder) 아키텍처&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;seq2seq 모델은 크게 두 부분으로 구성됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;인코더 (Encoder)&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;인코더는 입력 시퀀스를 처리하여&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;컨텍스트 벡터(Context Vector)를&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;* 시퀀스: 시간적 순서 또는 일정한 순서에 따라 배열된 데이터의 집합을 의미함. 이는 데이터가 순차적으로 의존관계를 가지며, 앞뒤의 데이터가 서로 연결되어 있는 경우를 말함. 예를 들어, 문장, 음성, 음악, 비디오 등이 모두 시퀀스 데이터의 예임.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;인코더는 다음과 같이 동작합니다.&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1️⃣ 시퀀스 데이터의 처리&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VkIsk/btsLBh2lXH4/VG3rtDgfW2pDE1FC4hsHsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VkIsk/btsLBh2lXH4/VG3rtDgfW2pDE1FC4hsHsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VkIsk/btsLBh2lXH4/VG3rtDgfW2pDE1FC4hsHsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVkIsk%2FbtsLBh2lXH4%2FVG3rtDgfW2pDE1FC4hsHsK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;313&quot; height=&quot;215&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;문장 &quot;I love cats&quot;를 예로 들면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1.&amp;nbsp;&lt;b&gt;첫 번째 입력: &quot;I&quot;&lt;/b&gt;&lt;br /&gt;- &lt;b&gt;입력&lt;/b&gt; &lt;br /&gt;단어 &amp;ldquo;l&amp;rdquo;의 임베딩 벡터 .&lt;br /&gt;초기 hidden state : 보통 [0, 0, 0] 또는 무작위 값으로 초기화.&lt;br /&gt;- &lt;b&gt;결과&lt;/b&gt; &lt;br /&gt;hidden state1: [0.2, -0.1, 0.1]&lt;br /&gt;&amp;nbsp;&lt;br /&gt;2.&amp;nbsp;&lt;b&gt;두 번째 입력: &amp;ldquo;love&amp;rdquo;&lt;/b&gt;&lt;br /&gt;- &lt;b&gt;입력&lt;/b&gt;&lt;br /&gt;단어 &amp;ldquo;love&amp;rdquo;의 임베딩 벡터.&lt;br /&gt;이전 hidden state : [0.2, -0.1, 0.1].&lt;br /&gt;- &lt;b&gt;결과&lt;/b&gt; &lt;br /&gt;hidden state2: [0.5, -0.2, 0.3].&lt;br /&gt;&amp;nbsp;&lt;br /&gt;3.&amp;nbsp;&lt;b&gt;세 번째 입력: &amp;ldquo;cat&amp;rdquo;&lt;/b&gt;&lt;br /&gt;- &lt;b&gt;입력&lt;/b&gt;&lt;br /&gt;단어 &amp;ldquo;cat&amp;rdquo;의 임베딩 벡터.&lt;br /&gt;이전 hidden state : [0.5, -0.2, 0.3].&lt;br /&gt;- &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;결과 &lt;br /&gt;hidden state3: [0.7, -0.3, 0.4].&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;이와 같이, 입력 단어들은 순차적으로 RNN을 통과하면서 hidden state를 업데이트하며, 입력 시퀀스의 마지막 hidden state가 컨텍스트 벡터로 사용됩니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2️⃣ 컨텍스트 벡터 생성&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uZHXn/btsLAa9F3sq/zyK37ByWQStyLMxKeUEiL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uZHXn/btsLAa9F3sq/zyK37ByWQStyLMxKeUEiL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uZHXn/btsLAa9F3sq/zyK37ByWQStyLMxKeUEiL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuZHXn%2FbtsLAa9F3sq%2FzyK37ByWQStyLMxKeUEiL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;525&quot; height=&quot;246&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;412&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;컨텍스트 벡터(context vector) 생성&lt;br /&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;- 마지막 hidden state : [0.7, -0.3, 0.4].&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;- 이 벡터는 입력 시퀀스의 정보를 압축한&amp;nbsp;컨텍스트 벡터로 사용됩니다.&lt;br /&gt;- 디코더는 이 컨텍스트 벡터를 바탕으로 출력 시퀀스를 생성합니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;* 컨텍스트 벡터(마지막 hidden state)는 입력 시퀀스 전체를 요약한 벡터입니다. 이 벡터는 입력 시퀀스에 대한 모든 중요한 정보를 담고 있으며, 디코더가 이를 기반으로 출력 시퀀스를 생성합니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;컨텍스트벡터는 &lt;b&gt;입력 문장의 길이와 관계없이 항상 같은 크기&lt;/b&gt;의 벡터로 변환합니다.&lt;br /&gt;예를 들어&lt;br /&gt;&amp;nbsp;- &quot;I&amp;nbsp;love&amp;nbsp;cats&quot;&amp;nbsp;(3 단어)&amp;nbsp;후&amp;rarr;&amp;nbsp;[0.8,&amp;nbsp;-0.5,&amp;nbsp;0.3]&amp;nbsp;(3차원&amp;nbsp;벡터)&lt;br /&gt;&amp;nbsp;- &quot;I&amp;nbsp;really&amp;nbsp;love&amp;nbsp;cute&amp;nbsp;cats&quot;&amp;nbsp;(5 단어)&amp;nbsp;&amp;rarr;&amp;nbsp;[0.7,&amp;nbsp;-0.6,&amp;nbsp;0.4]&amp;nbsp;(같은&amp;nbsp;3차원&amp;nbsp;벡터)&lt;br /&gt;이렇게 다른 길이의 문장도 같은 크기의 벡터로 표현됩니다.&lt;br /&gt;&lt;br /&gt;이런 과정을 통해 인코더는 가변 길이의 입력 문장을 &lt;b&gt;고정된 크기의 의미 있는 벡터&lt;/b&gt;로 변환할 수 있습니다.&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;디코더 (Decoder)&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;디코더는 인코더에서 받은 &lt;b&gt;컨텍스트 벡터&lt;/b&gt;를 바탕으로 출력 시퀀스를 생성합니다. 디코더도 RNN 기반 구조를 가지며, 다음과 같이 동작합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uZHXn/btsLAa9F3sq/zyK37ByWQStyLMxKeUEiL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uZHXn/btsLAa9F3sq/zyK37ByWQStyLMxKeUEiL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uZHXn/btsLAa9F3sq/zyK37ByWQStyLMxKeUEiL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuZHXn%2FbtsLAa9F3sq%2FzyK37ByWQStyLMxKeUEiL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;525&quot; height=&quot;246&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;412&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1️⃣ &lt;b&gt;컨텍스트 벡터로 초기화&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;인코더에서 생성된 컨텍스트 벡터를 첫 hidden state로 사용하여 출력을 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- &lt;b&gt;초기 hidden state&lt;/b&gt;: &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;컨텍스트 벡터 [0.7, -0.3, 0.4]&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- &lt;b&gt;초기 입력&lt;/b&gt;: 시작 토큰 &lt;span&gt;&amp;lt;sos&amp;gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2️⃣ &lt;b&gt;출력 시퀀스 생성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;입력 토큰(&lt;span&gt;&amp;lt; sos&amp;gt;&lt;/span&gt;)&lt;/b&gt;과 &lt;b&gt;hidden state&lt;/b&gt;를 사용하여 다음 단어를 예측합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;예를 들어, &amp;ldquo;I love cats&amp;rdquo;라는 문장의 출력을 생성하는 과정을 단계적으로 살펴보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;1.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;첫 번째 예측&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;입력&lt;/b&gt;: &amp;lt;sos&amp;gt; 토큰 + 초기 hidden state &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;[0.7, -0.3, 0.4]&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;출력&lt;/b&gt;: &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&quot;I&quot;&lt;/span&gt; + 업데이트된 hidden state, cell state&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;2.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;두 번째 예측&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;입력&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;: &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&quot;I&quot;&lt;/span&gt; +&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;첫 번째 예측에서 계산된 hidden state, cell state&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;출력&lt;/b&gt;: &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&quot;love&quot;&lt;/span&gt; + 업데이트된 hidden state, cell state&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;3.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;세 번째 예측&lt;/b&gt;&lt;br /&gt;- &lt;b&gt;입력&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;: &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&quot;love&quot;&lt;/span&gt; +&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;두 번째 예측에서 계산된 hidden state, cell state&lt;/b&gt;&lt;br /&gt;- &lt;b&gt;출력&lt;/b&gt;: &lt;span style=&quot;background-color: #9feec3;&quot;&gt;&quot;cats&quot;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4. &lt;b&gt;종료&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- &lt;b&gt;입력&lt;/b&gt;: &lt;span style=&quot;background-color: #9feec3;&quot;&gt;&amp;ldquo;cats&amp;rdquo;&lt;/span&gt; (세 번째 출력 단어) + &lt;b&gt;세&amp;nbsp;번째 예측에서 계산된 hidden state, cell state&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;- &lt;b&gt;출력&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;b&gt;단어: &lt;span&gt;&amp;lt;eos&amp;gt;&lt;/span&gt; (종료 토큰)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;디코더는 종료 토큰을 예측한 후 작업을 멈춥니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;디코더 과정에서 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;Teacher Forcing&lt;/b&gt;&lt;/span&gt; 기법이 사용될 수 있습니다. (학습 시 &lt;b&gt;정답 토큰을 입력으로 사용하는 방법&lt;/b&gt;).&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Teacher Forcing 기법&lt;/b&gt;&lt;br /&gt;학습 과정에서만 사용되는 특별한 방법입니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;일반적인 방식과 Teacher Forcing의 차이&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;Teacher Forcing 사용 시 &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;입력: &amp;lt;START&amp;gt; &amp;rarr; 출력: &quot;나는&quot; (정답 사용) &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;입력: &quot;나는&quot;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;rarr; 출력: &quot;고양이를&quot; (정답 사용) &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;입력: &quot;고양이를&quot; &amp;rarr; 출력: &quot;좋아해&quot; (정답 사용) &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span&gt;Teacher Forcing 미사용 시 &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;입력: &amp;lt;START&amp;gt; &amp;rarr; 출력: &quot;나는&quot; (예측값 사용) &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;입력: &quot;나는&quot;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;rarr; 출력: &quot;강아지를&quot; (잘못된 예측) &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;입력: &quot;고양이를&quot; &amp;rarr; 출력: &quot;좋아해&quot; (오류 전파)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;학습 시: 모델이&lt;u&gt;&lt;i&gt;&lt;b&gt;&quot;강아지를&quot;이라고 잘못 예측했더라도, &lt;br /&gt;다음 입력으로 정답인 &quot;고양이를&quot;을 사용하여 학습하는 방법&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;입니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;이렇게 하면 한 번의 오류가 후속 예측에 영향을 주지 않아 학습이 더 안정적입니다. &lt;br /&gt;하지만 &lt;b&gt;추론(Inference)&lt;/b&gt;할 때는 정답을 알 수 없으므로, 모델이 생성한 출력을 그대로 다음 입력으로 사용합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;  hidden state는 어떻게 업데이트되나요?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;RNN, LSTM, GRU와 같은 순환 구조를 사용하며, 이들은 다음과 같은 방식으로 hidden state를 업데이트합니다.&lt;br /&gt;1. &lt;b&gt;입력&lt;/b&gt;: 현재 단어(&quot;나는&quot;)와 이전 hidden state&lt;br /&gt;2. &lt;b&gt;계산&lt;/b&gt;: RNN/LSTM/GRU가 입력 데이터를 처리하여 새로운 hidden state를 계산&lt;br /&gt;3. &lt;b&gt;출력&lt;/b&gt;: 다음 단어를 예측하고, 새로운 hidden state를 반환&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt; &amp;nbsp; 왜 &quot;순환 신경망을 사용&quot; 할까?&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;RNN은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;이전 시점의 정보&lt;/b&gt;&lt;/span&gt;를 현재 시점의 처리에 활용할 수 있습니다.&amp;nbsp;예를 들어 &quot;cats&quot;를 처리할 때, 앞에 나온 &quot;I&quot;와 &quot;love&quot;의 정보도 함께 고려됩니다.&amp;nbsp;이를 통해 문장의 순서와 문맥 정보를 보존할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;b&gt;  &lt;/b&gt;단순 벡터 변환&amp;nbsp; &lt;/b&gt;vs. &lt;b&gt;컨텍스트 벡터&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;단순히 벡터로 변환하는 임베딩 벡터와 컨텍스트 벡터는 다른 용어인데요. 어떤 차이가 있는지 보시죠.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1204&quot; data-origin-height=&quot;230&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1YGfV/btsLobVuGUj/MHzdzPvfDvopBDznAasYgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1YGfV/btsLobVuGUj/MHzdzPvfDvopBDznAasYgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1YGfV/btsLobVuGUj/MHzdzPvfDvopBDznAasYgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1YGfV%2FbtsLobVuGUj%2FMHzdzPvfDvopBDznAasYgK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;530&quot; height=&quot;101&quot; data-origin-width=&quot;1204&quot; data-origin-height=&quot;230&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;단순 벡터 변환&lt;/b&gt;&lt;br /&gt;- 입력 데이터(예: 단어)를 임베딩(embedding)하여 고정된 차원의 벡터로 표현합니다.&lt;br /&gt;- 예: &quot;I&quot; &amp;rarr; [0.2, 0.8], &quot;love&quot; &amp;rarr; [0.5, 0.1], &quot;cats&quot; &amp;rarr; [0.3, 0.6].&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;Seq2Seq의 컨텍스트 벡터&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;- 단순히 단어를 벡터로 변환하는 것을 넘어,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;입력 시퀀스의 순서와 의미를 학습&lt;/b&gt;한 결과입니다.&lt;br /&gt;- Encoder는 RNN, LSTM, GRU 같은 순환 구조를 통해 시퀀스를 순차적으로 처리하며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이전 단어들과의 관계를 반영한 hidden state&lt;/b&gt;를 생성합니다.&lt;br /&gt;- 마지막 hidden state(컨텍스트 벡터)는 단어 간의 연관성과 문맥적 의미를 포함합니다.&lt;br /&gt;- 예: &quot;I love cats&quot; &amp;rarr; [0.7, -0.4, 0.3]&lt;br /&gt;(이 값은 &quot;I&quot;, &quot;love&quot;, &quot;cats&quot;의 관계와 순서를 반영한 결과)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;seq2seq 모델의 주요 특징&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1️⃣ 가변 길이의 입력을 받아서 가변 길이의 출력을 생성할 수 있습니다.&lt;/b&gt; &lt;br /&gt;입력 문장의 길이가 고정되어 있지 않아도 된다는 의미인데요.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;예를 들어, 번역 작업에서&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;&quot;I&amp;nbsp;am&amp;nbsp;happy&quot;&amp;nbsp;(3 단어)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;&quot;I&amp;nbsp;am&amp;nbsp;very&amp;nbsp;very&amp;nbsp;happy&amp;nbsp;today&quot;&amp;nbsp;(6 단어)&lt;br /&gt;이렇게 길이가 다른 두 문장 모두를 입력으로 처리할 수 있습니다.&lt;br /&gt;전통적인 신경망은 보통 고정된 크기의 입력만 받을 수 있었지만, seq2seq는 이런 제약이 없습니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;b&gt;2️⃣ 문맥을 고려한 시퀀스 생성이 가능&lt;/b&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;이는 출력을 생성할 때 전체 입력 문장의 의미를 고려한다는 의미입니다.&lt;br /&gt;&amp;nbsp;예를 들어, &quot;bank&quot;라는 단어를 번역할 때&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;&quot;I&amp;nbsp;went&amp;nbsp;to&amp;nbsp;the&amp;nbsp;bank&amp;nbsp;to&amp;nbsp;withdraw&amp;nbsp;money&quot;&amp;nbsp;&amp;rarr;&amp;nbsp;&quot;은행&quot;으로&amp;nbsp;번역&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;&quot;I&amp;nbsp;sat&amp;nbsp;by&amp;nbsp;the&amp;nbsp;river&amp;nbsp;bank&quot;&amp;nbsp;&amp;rarr;&amp;nbsp;&quot;강둑&quot;으로&amp;nbsp;번역&lt;br /&gt;이처럼 같은 단어라도 문장 전체의 문맥을 보고 적절한 의미를 선택할 수 있습니다. 이는 인코더가 입력 문장 전체의 정보를 압축해서 저장하고, 디코더가 이 정보를 바탕으로 출력을 생성하기 때문에 가능합니다.&lt;br /&gt;&lt;br /&gt;예시를 하나 더 들어보겠습니다&lt;br /&gt;문장:&amp;nbsp;&quot;The&amp;nbsp;movie&amp;nbsp;was&amp;nbsp;not&amp;nbsp;bad&amp;nbsp;at&amp;nbsp;all&quot;&lt;br /&gt;이&amp;nbsp;문장을&amp;nbsp;한국어로&amp;nbsp;번역할&amp;nbsp;때,&amp;nbsp;seq2seq는&amp;nbsp;&quot;not&amp;nbsp;bad&quot;라는&amp;nbsp;표현이&amp;nbsp;실제로는&amp;nbsp;긍정적인&amp;nbsp;의미라는&amp;nbsp;것을&amp;nbsp;문맥상에서&amp;nbsp;파악하여&amp;nbsp;&quot;영화가&amp;nbsp;꽤&amp;nbsp;좋았다&quot;와&amp;nbsp;같이&amp;nbsp;적절하게&amp;nbsp;번역할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;단순히&amp;nbsp;단어&amp;nbsp;단위로&amp;nbsp;번역하면&amp;nbsp;&quot;영화는&amp;nbsp;나쁘지&amp;nbsp;않았다&quot;가&amp;nbsp;되어&amp;nbsp;뉘앙스가&amp;nbsp;달라질&amp;nbsp;수&amp;nbsp;있습니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;b&gt;3️⃣ 입력과 출력의 길이가 서로 다를 수 있음&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  Seq2Seq 모델의 한계점&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&lt;b&gt;1.&amp;nbsp;긴&amp;nbsp;시퀀스&amp;nbsp;처리의&amp;nbsp;한계&lt;/b&gt;&lt;br /&gt;-&amp;nbsp;입력&amp;nbsp;시퀀스가&amp;nbsp;길어질수록&amp;nbsp;정보&amp;nbsp;손실이&amp;nbsp;발생&lt;br /&gt;-&amp;nbsp;초기에&amp;nbsp;입력된&amp;nbsp;정보가&amp;nbsp;마지막&amp;nbsp;컨텍스트&amp;nbsp;벡터에&amp;nbsp;충분히&amp;nbsp;반영되지&amp;nbsp;못하는&amp;nbsp;문제&amp;nbsp;(장기&amp;nbsp;의존성&amp;nbsp;문제)&lt;br /&gt;-&amp;nbsp;예시:&amp;nbsp;&quot;Last&amp;nbsp;month,&amp;nbsp;I&amp;nbsp;went&amp;nbsp;to&amp;nbsp;Paris...&quot;로&amp;nbsp;시작하는&amp;nbsp;긴&amp;nbsp;문장에서&amp;nbsp;마지막&amp;nbsp;부분을&amp;nbsp;생성할&amp;nbsp;때&amp;nbsp;&quot;Last&amp;nbsp;month&quot;라는&amp;nbsp;시간&amp;nbsp;정보가&amp;nbsp;잘&amp;nbsp;반영되지&amp;nbsp;않을&amp;nbsp;수&amp;nbsp;있음&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2.&amp;nbsp;고정&amp;nbsp;크기&amp;nbsp;컨텍스트&amp;nbsp;벡터의&amp;nbsp;병목&amp;nbsp;현상&lt;/b&gt;&lt;br /&gt;-&amp;nbsp;입력&amp;nbsp;문장의&amp;nbsp;길이와&amp;nbsp;관계없이&amp;nbsp;항상&amp;nbsp;같은&amp;nbsp;크기의&amp;nbsp;컨텍스트&amp;nbsp;벡터를&amp;nbsp;사용&lt;br /&gt;-&amp;nbsp;긴&amp;nbsp;문장의&amp;nbsp;경우&amp;nbsp;모든&amp;nbsp;정보를&amp;nbsp;제한된&amp;nbsp;크기의&amp;nbsp;벡터에&amp;nbsp;압축하다&amp;nbsp;보니&amp;nbsp;정보&amp;nbsp;손실이&amp;nbsp;불가피&lt;br /&gt;-&amp;nbsp;이는&amp;nbsp;나중에&amp;nbsp;어텐션(Attention)&amp;nbsp;메커니즘의&amp;nbsp;도입&amp;nbsp;계기가&amp;nbsp;됨&lt;br /&gt;&lt;br /&gt;&lt;b&gt;3.&amp;nbsp;출력&amp;nbsp;생성의&amp;nbsp;일관성&amp;nbsp;문제&lt;/b&gt;&lt;br /&gt;-&amp;nbsp;한&amp;nbsp;번&amp;nbsp;잘못된&amp;nbsp;예측을&amp;nbsp;하면&amp;nbsp;그&amp;nbsp;오류가&amp;nbsp;이후&amp;nbsp;생성에&amp;nbsp;계속&amp;nbsp;영향을&amp;nbsp;미침&lt;br /&gt;-&amp;nbsp;예시:&amp;nbsp;&quot;I&amp;nbsp;am&quot;&amp;nbsp;&amp;rarr;&amp;nbsp;&quot;나는&quot;&amp;nbsp;&amp;rarr;&amp;nbsp;&quot;사과를&quot;&amp;nbsp;&amp;rarr;&amp;nbsp;&quot;먹었다&quot;&lt;br /&gt;&amp;nbsp;&amp;nbsp;만약&amp;nbsp;&quot;나는&quot;&amp;nbsp;대신&amp;nbsp;&quot;그는&quot;이라고&amp;nbsp;잘못&amp;nbsp;예측하면,&amp;nbsp;이후&amp;nbsp;문장의&amp;nbsp;일관성이&amp;nbsp;무너질&amp;nbsp;수&amp;nbsp;있음&lt;br /&gt;&lt;br /&gt;&lt;b&gt;4.&amp;nbsp;연산&amp;nbsp;비용과&amp;nbsp;속도&lt;/b&gt;&lt;br /&gt;-&amp;nbsp;시퀀스를&amp;nbsp;순차적으로&amp;nbsp;처리해야&amp;nbsp;하므로&amp;nbsp;병렬&amp;nbsp;처리가&amp;nbsp;어려움&lt;br /&gt;-&amp;nbsp;특히&amp;nbsp;긴&amp;nbsp;시퀀스의&amp;nbsp;경우&amp;nbsp;처리&amp;nbsp;시간이&amp;nbsp;크게&amp;nbsp;증가&lt;br /&gt;-&amp;nbsp;GPU를&amp;nbsp;활용한&amp;nbsp;병렬&amp;nbsp;처리의&amp;nbsp;이점을&amp;nbsp;충분히&amp;nbsp;활용하기&amp;nbsp;어려움&lt;br /&gt;&lt;br /&gt;&lt;b&gt;5.&amp;nbsp;단방향&amp;nbsp;문맥&amp;nbsp;이해의&amp;nbsp;한계&lt;/b&gt;&lt;br /&gt;-&amp;nbsp;기본적인&amp;nbsp;seq2seq는&amp;nbsp;입력을&amp;nbsp;순차적으로만&amp;nbsp;처리&lt;br /&gt;-&amp;nbsp;문장의&amp;nbsp;전체적인&amp;nbsp;문맥을&amp;nbsp;양방향으로&amp;nbsp;이해하는&amp;nbsp;데&amp;nbsp;한계가&amp;nbsp;있음&lt;br /&gt;-&amp;nbsp;이는&amp;nbsp;나중에&amp;nbsp;양방향&amp;nbsp;RNN&amp;nbsp;(Bidirectional&amp;nbsp;RNN)의&amp;nbsp;도입&amp;nbsp;계기가&amp;nbsp;됨&lt;br /&gt;&lt;br /&gt;&lt;b&gt; &amp;nbsp;이러한&amp;nbsp;한계점들을&amp;nbsp;극복하기&amp;nbsp;위한&amp;nbsp;후속&amp;nbsp;발전&lt;/b&gt;&lt;br /&gt;-&amp;nbsp;어텐션&amp;nbsp;메커니즘&amp;nbsp;도입&lt;br /&gt;-&amp;nbsp;Transformer&amp;nbsp;아키텍처&amp;nbsp;개발&lt;br /&gt;-&amp;nbsp;양방향&amp;nbsp;인코더&amp;nbsp;사용&lt;br /&gt;-&amp;nbsp;빔&amp;nbsp;서치(Beam&amp;nbsp;Search)&amp;nbsp;같은&amp;nbsp;디코딩&amp;nbsp;전략&amp;nbsp;도입&lt;br /&gt;&lt;br /&gt;이러한&amp;nbsp;한계점들은&amp;nbsp;seq2seq&amp;nbsp;모델이&amp;nbsp;발전하는&amp;nbsp;과정에서&amp;nbsp;새로운&amp;nbsp;아키텍처와&amp;nbsp;기법들이&amp;nbsp;등장하는&amp;nbsp;계기가&amp;nbsp;되었으며,&amp;nbsp;현대의&amp;nbsp;많은&amp;nbsp;자연어&amp;nbsp;처리&amp;nbsp;모델들은&amp;nbsp;이러한&amp;nbsp;문제들을&amp;nbsp;해결하기&amp;nbsp;위한&amp;nbsp;다양한&amp;nbsp;개선&amp;nbsp;방법들을&amp;nbsp;포함하고&amp;nbsp;있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;pre id=&quot;code_1735605937157&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Encoder(nn.Module):
    def __init__(self, src_vocab_size, embedding_dim, hidden_units):
        super(Encoder, self).__init__()
        self.embedding = nn.Embedding(src_vocab_size, embedding_dim, padding_idx=0)
        self.lstm = nn.LSTM(embedding_dim, hidden_units, batch_first=True)

    def forward(self, x):     # x.shape == (batch_size, seq_len)
        # 1.단어 임베딩
        x = self.embedding(x) # 임베딩층 통과 후 x.shape = (batch_size, seq_len, embedding_dim)
        # 2.LSTM 처리
        _, (hidden, cell) = self.lstm(x) # hidden.shape == (1, batch_size, hidden_units), cell.shape == (1, batch_size, hidden_units)
        return hidden, cell # 인코더의 출력은 hidden state, cell state&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1735605947919&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Decoder(nn.Module):
    def __init__(self, tar_vocab_size, embedding_dim, hidden_units):
        super(Decoder, self).__init__()
        self.embedding = nn.Embedding(tar_vocab_size, embedding_dim, padding_idx=0)
        self.lstm = nn.LSTM(embedding_dim, hidden_units, batch_first=True)
        self.fc = nn.Linear(hidden_units, tar_vocab_size)

    def forward(self, x, hidden, cell): # x.shape == (batch_size, seq_len)
        # 1. 단어 임베딩
        x = self.embedding(x) # x.shape == (batch_size, seq_len, embedding_dim)

        # 2.LSTM 처리
        # 디코더의 LSTM으로 인코더의 hidden state, cell state를 전달.
        # output.shape == (batch_size, seq_len, hidden_units)
        # hidden.shape == (1, batch_size, hidden_units)
        # cell.shape == (1, batch_size, hidden_units)
        output, (hidden, cell) = self.lstm(x, (hidden, cell))
        # 3.출력 예측
        output = self.fc(output) # output.shape: (batch_size, seq_len, tar_vocab_size)

        # 디코더의 출력은 예측값, hidden state, cell state
        return output, hidden, cell&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1735605953194&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Seq2Seq(nn.Module):
    def __init__(self, encoder, decoder):
        super(Seq2Seq, self).__init__()
        self.encoder = encoder
        self.decoder = decoder

    def forward(self, src, trg):
        hidden, cell = self.encoder(src) # 인코더 입력 (정수 인코딩된 소스 시퀀스, 예: 영어 문장).

        # 훈련 중에는 디코더의 출력 중 오직 output만 사용한다.
        output, _, _ = self.decoder(trg, hidden, cell) # 디코더 입력 (정수 인코딩된 타겟 시퀀스, 예: 프랑스어 문장).
        return output
    
encoder = Encoder(src_vocab_size, embedding_dim, hidden_units)
decoder = Decoder(tar_vocab_size, embedding_dim, hidden_units)
model = Seq2Seq(encoder, decoder)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>pytorch</category>
      <category>Decoder</category>
      <category>Encoder</category>
      <category>nlp</category>
      <category>seq2seq</category>
      <category>디코더</category>
      <category>시퀀스투시퀀스</category>
      <category>어텐션메커니즘</category>
      <category>인공지능</category>
      <category>인코더</category>
      <category>자연어처리</category>
      <author>ISFP의 블로그</author>
      <guid isPermaLink="true">https://resultofeffort.tistory.com/148</guid>
      <comments>https://resultofeffort.tistory.com/148#entry148comment</comments>
      <pubDate>Tue, 31 Dec 2024 09:44:17 +0900</pubDate>
    </item>
    <item>
      <title>[pytorch] 코사인 유사도(Cosine Similarity) | 유클리드 거리 (Euclidean Distance) | 자카드 유사도(Jaccard Similarity) | 코사인 유사도를 이용한 영화 추천 시스템 | cosine_similarity</title>
      <link>https://resultofeffort.tistory.com/147</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;앞서 TF-IDF (Term Frequency-Inverse Document Frequency)를 사용하여 텍스트 데이터를 벡터화하는 방법을 배웠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이제, 이 TF-IDF 벡터를 활용하여 문서 간 유사도를 계산해보려 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;텍스트 데이터의 유사도를 측정하는 방법으로는 여러 가지가 있지만, 이번에는 &lt;b&gt;코사인 유사도 (Cosine Similarity)&lt;/b&gt;, &lt;b&gt;유클리드 거리 (Euclidean Distance)&lt;/b&gt;, 그리고 자카드 유사도 (Jaccard Similarity)를 사용하여 영화 추천 시스템을 구축해 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;유클리드 거리 vs 코사인 유사도 vs 자카드 유사도 비교&lt;/b&gt;&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 104.302%; height: 533px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #9b9b9b; color: #ffffff; text-align: center;&quot;&gt;&lt;b&gt;기준&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #9b9b9b; color: #ffffff; text-align: center;&quot;&gt;&lt;b&gt;유클리드 거리&lt;br /&gt;(Euclidean Distance)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #9b9b9b; color: #ffffff; text-align: center;&quot;&gt;&lt;b&gt;코사인 유사도&lt;br /&gt;(Cosine Similarity)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #9b9b9b; color: #ffffff; text-align: center;&quot;&gt;&lt;span&gt;&lt;b&gt;자카드 유사도&lt;br /&gt;(Jaccard Similarity)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #efefef; text-align: center;&quot;&gt;&lt;b&gt;측정 방식&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;벡터 간의 직선 거리&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;벡터 간의 각도&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span&gt;두 집합 간의 교집합과 합집합 비율&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #efefef; text-align: center;&quot;&gt;&lt;b&gt;벡터 크기 영향&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9; text-align: center;&quot;&gt;벡터의 크기에 민감&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9; text-align: center;&quot;&gt;벡터의 크기를 무시하고 방향만 고려&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9; text-align: center;&quot;&gt;&lt;span&gt;벡터의 크기보다는 단어의 존재 여부에 중점&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #efefef; text-align: center;&quot;&gt;&lt;b&gt;주요 활용 분야&amp;nbsp;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;수치 데이터 분석, 좌표 거리 측정&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;텍스트 데이터 분석, 추천 시스템&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span&gt;문서 유사도 분석, 검색 엔진 최적화&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #efefef; text-align: center;&quot;&gt;&lt;b&gt;스케일링 필요 여부&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9; text-align: center;&quot;&gt;필수&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9; text-align: center;&quot;&gt;불필요&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9; text-align: center;&quot;&gt;&lt;span&gt;불필요&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #efefef; text-align: center;&quot;&gt;&lt;b&gt;회소 행렬에서의 성능&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;부정확한 결과 가능&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;상대적으로 효율적&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span&gt;공통 단어가 적을 경우 부정확&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #efefef; text-align: center;&quot;&gt;&lt;b&gt;문서 길이 영향&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9; text-align: center;&quot;&gt;영향 있음&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9; text-align: center;&quot;&gt;영향 없음&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9; text-align: center;&quot;&gt;&lt;span&gt;영향 없음 (단어의 존재 여부만 반영)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #efefef; text-align: center;&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span&gt;- 좌표 공간에서의 실제 거리 측정 가능&lt;span&gt;&amp;nbsp;&lt;br /&gt;&lt;/span&gt;- 수치 데이터 분석에 유리&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span&gt;- 텍스트 데이터에서 문서 길이와 관계없이&lt;br /&gt;유사도 평가 가능&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span&gt;- 단어의 존재 여부만으로 유사도 측정 가능&lt;span&gt;&amp;nbsp;&lt;br /&gt;&lt;/span&gt;- 빠른 계산 속도&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #efefef; text-align: center;&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9; text-align: center;&quot;&gt;&lt;span&gt;- 벡터의 크기에 민감하여 텍스트 데이터에 부적합&lt;span&gt;&amp;nbsp;&lt;br /&gt;&lt;/span&gt;- 스케일링 필요&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9; text-align: center;&quot;&gt;&lt;span&gt;- 단어 간 문맥을 고려하지 못함&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9; text-align: center;&quot;&gt;&lt;span&gt;- 단어가 희귀할 경우 유사도 평가가 어려움&lt;span&gt;&amp;nbsp;&lt;br /&gt;&lt;/span&gt;- 연속형 데이터에는 부적합&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;- 코사인 유사도&lt;/b&gt;는 두 벡터 간의 방향을 기준으로 유사도를 측정합니다. 벡터의 크기와 관계없이 방향이 유사할수록 높은 유사도로 평가되기 때문에, 텍스트 데이터나 추천 시스템에서 자주 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- &lt;b&gt;유클리드 거리&lt;/b&gt;는 두 벡터 간의 직선거리를 측정합니다. 벡터 간의 거리가 가까울수록 두 텍스트가 더 유사하다고 판단합니다. 다만, 벡터의 크기에 영향을 받기 때문에 문서 길이에 따라 왜곡된 결과를 초래할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- &lt;b&gt;자카드 유사도&lt;/b&gt;는 두 집합 간의 유사도를 측정하는 방법으로, 공통된 요소의 비율을 기반으로 합니다. 텍스트 데이터를 집합 형태로 변환하여 단어의 중복도를 제거하고, 두 텍스트 간의 공통된 단어 비율을 비교합니다. 이 방법은 텍스트의 내용이 유사하지만 단어 빈도가 다른 경우에도 문서 간의 유사성을 잘 평가할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이제, 각 유사도 측정 방법을 활용하여 영화 줄거리 데이터를 분석하고, 사용자가 입력한 영화와 유사한 영화를 추천하는 시스템을 만들어 보겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;코사인 유사도(Cosine Similarity)란?&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;코사인 유사도는 두 벡터 간의 &lt;b&gt;각도를 이용해 유사도를 측정&lt;/b&gt;하는 방법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;벡터의 크기가 아니라 &lt;b&gt;방향이 얼마나 유사한지&lt;/b&gt;를 평가하기 때문에, &lt;b&gt;텍스트 데이터나 추천 시스템&lt;/b&gt;에서 자주 활용됩니다.&lt;br /&gt;&lt;br /&gt;\[&lt;br /&gt;\text {Cosine&amp;nbsp;Similarity}(A,&amp;nbsp;B)&amp;nbsp;=&amp;nbsp;\frac {A&amp;nbsp;\cdot&amp;nbsp;B}{\|A\|&amp;nbsp;\|B\|}&lt;br /&gt;\]&lt;br /&gt;&lt;br /&gt;-&amp;nbsp;\(&amp;nbsp;A&amp;nbsp;\cdot&amp;nbsp;B&amp;nbsp;\):&amp;nbsp;두&amp;nbsp;벡터의&amp;nbsp;내적&lt;br /&gt;-&amp;nbsp;\(&amp;nbsp;\|A\|&amp;nbsp;\):&amp;nbsp;벡터&amp;nbsp;\(&amp;nbsp;A&amp;nbsp;\)의&amp;nbsp;크기(길이)&lt;br /&gt;-&amp;nbsp;\(&amp;nbsp;\|B\|&amp;nbsp;\):&amp;nbsp;벡터&amp;nbsp;\(&amp;nbsp;B&amp;nbsp;\)의&amp;nbsp;크기(길이)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;(문서 단어 행렬이나 TF-IDF 행렬을 통해서 문서의 유사도를 구하는 경우에는 문서 단어 행렬이나 &lt;b&gt;TF-IDF 행렬&lt;/b&gt;이 각각의 &lt;b&gt;벡터 A, B&lt;/b&gt;가 됩니다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;코사인 유사도의 값이&lt;br /&gt;- &lt;b&gt;1에 가까울수록 두 벡터가 유사함&lt;/b&gt;을 의미합니다.&lt;br /&gt;- 0에 가까울수록 두 벡터가 서로 직각임을 의미합니다(즉, 유사하지 않음).&lt;br /&gt;- -1에 가까울수록 두 벡터가 반대 방향을 가리킴을 의미합니다(이 경우는 텍스트나 추천 시스템에서 거의 발생하지 않음).&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;i&gt;&lt;b&gt;코사인 유사도가 벡터의 크기에 영향을 받지 않는 이유&lt;/b&gt;&lt;/i&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식에서 보시다시피, 코사인 유사도는 &lt;b&gt;두 벡터의 내적을 각 벡터의 크기(길이)로 나눕니다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이 과정을 통해 &lt;b&gt;벡터의 크기를 정규화&lt;/b&gt;하게 됩니다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;즉, &lt;b&gt;벡터의 크기가 아무리 커도&lt;/b&gt; 내적 값은 그 크기로 &lt;b&gt;나눠&lt;/b&gt;지기 때문에 &lt;b&gt;결과적으로 크기(길이)의 영향을 제거&lt;/b&gt;하게 됩니다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;예를 들어,&lt;br /&gt;&lt;b&gt;벡터의 크기가 다른 경우&lt;/b&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;벡터&amp;nbsp;\(&amp;nbsp;A&amp;nbsp;=&amp;nbsp;[1,&amp;nbsp;1]&amp;nbsp;\)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;벡터&amp;nbsp;\(&amp;nbsp;B&amp;nbsp;=&amp;nbsp;[2,&amp;nbsp;2]&amp;nbsp;\)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;코사인 유사도 계산&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\[&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;A&amp;nbsp;\cdot&amp;nbsp;B&amp;nbsp;=&amp;nbsp;1&amp;nbsp;\times&amp;nbsp;2&amp;nbsp;+&amp;nbsp;1&amp;nbsp;\times&amp;nbsp;2&amp;nbsp;=&amp;nbsp;4&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\[&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\|A\|&amp;nbsp;=&amp;nbsp;\sqrt {1^2&amp;nbsp;+&amp;nbsp;1^2}&amp;nbsp;=&amp;nbsp;\sqrt {2},&amp;nbsp;\quad&amp;nbsp;\|B\|&amp;nbsp;=&amp;nbsp;\sqrt {2^2&amp;nbsp;+&amp;nbsp;2^2}&amp;nbsp;=&amp;nbsp;\sqrt {8}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\[&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\text {Cosine&amp;nbsp;Similarity}(A,&amp;nbsp;B)&amp;nbsp;=&amp;nbsp;\frac {4}{\sqrt {2}&amp;nbsp;\times&amp;nbsp;\sqrt {8}}&amp;nbsp;=&amp;nbsp;\frac {4}{4}&amp;nbsp;=&amp;nbsp;1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;결과적으로, &lt;b&gt;벡터의 크기가 다르지만 방향이 동일하기 때문에 코사인 유사도는 1&lt;/b&gt;이 됩니다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;벡터의 방향이 다른 경우&lt;/b&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;벡터&amp;nbsp;\(&amp;nbsp;A&amp;nbsp;=&amp;nbsp;[1,&amp;nbsp;0]&amp;nbsp;\)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;벡터&amp;nbsp;\(&amp;nbsp;B&amp;nbsp;=&amp;nbsp;[0,&amp;nbsp;1]&amp;nbsp;\)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;코사인 유사도 계산&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\[&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;A&amp;nbsp;\cdot&amp;nbsp;B&amp;nbsp;=&amp;nbsp;1&amp;nbsp;\times&amp;nbsp;0&amp;nbsp;+&amp;nbsp;0&amp;nbsp;\times&amp;nbsp;1&amp;nbsp;=&amp;nbsp;0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\[&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\|A\|&amp;nbsp;=&amp;nbsp;\sqrt {1^2&amp;nbsp;+&amp;nbsp;0^2}&amp;nbsp;=&amp;nbsp;1,&amp;nbsp;\quad&amp;nbsp;\|B\|&amp;nbsp;=&amp;nbsp;\sqrt {0^2&amp;nbsp;+&amp;nbsp;1^2}&amp;nbsp;=&amp;nbsp;1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\[&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\text {Cosine&amp;nbsp;Similarity}(A,&amp;nbsp;B)&amp;nbsp;=&amp;nbsp;\frac {0}{1&amp;nbsp;\times&amp;nbsp;1}&amp;nbsp;=&amp;nbsp;0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;여기서, &lt;b&gt;벡터의 크기가 같아도 방향이 다르기 때문에 코사인 유사도는 0&lt;/b&gt;이 됩니다.&lt;br /&gt;&lt;br /&gt;정리하자면,&lt;br /&gt;코사인 유사도는 &lt;b&gt;벡터의 크기를 정규화&lt;/b&gt;하기 때문에, &lt;b&gt;벡터의 길이(크기)&lt;/b&gt;에는 영향을 받지 않습니다. 대신, 두 벡터의 &lt;b&gt;방향(각도)&lt;/b&gt;에만 초점을 맞추어 유사도를 측정합니다. 따라서 &lt;b&gt;문서의 길이(단어 수)와 관계없이&lt;/b&gt;, &lt;b&gt;내용의 유사성&lt;/b&gt;을 더 잘 평가할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;텍스트 데이터에서 코사인 유사도는 어떻게 계산할까?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;예를 들어, 세 개의 문서에 대해 TF-IDF를 계산했다고 가정해 보겠습니다.&lt;br /&gt;&lt;br /&gt;1. 문서 1의 TF-IDF 결과: `[0.5, 0.3, 0.0, 0.2]`&lt;br /&gt;2. 문서 2의 TF-IDF 결과: `[0.1, 0.7, 0.0, 0.4]`&lt;br /&gt;3. 문서 3의 TF-IDF 결과: `[0.0, 0.2, 0.6, 0.1]`&lt;br /&gt;&lt;br /&gt;TF-IDF 벡터를 사용해 코사인 유사도를 계산하는 과정은 다음과 같습니다.&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;\[&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;\text{Cosine&amp;nbsp;Similarity}(A,&amp;nbsp;B)&amp;nbsp;=&amp;nbsp;\frac {A&amp;nbsp;\cdot&amp;nbsp;B}{\|A\|&amp;nbsp;\times&amp;nbsp;\|B\|}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;\]&lt;br /&gt;&lt;br /&gt;만약, 우리가 문서 1과 문서 2의 코사인 유사도를 계산한다고 가정해 보겠습니다.&lt;br /&gt;&lt;br /&gt;-&amp;nbsp;문서&amp;nbsp;1의&amp;nbsp;벡터:&amp;nbsp;`[0.5,&amp;nbsp;0.3,&amp;nbsp;0.0,&amp;nbsp;0.2]`&lt;br /&gt;-&amp;nbsp;문서&amp;nbsp;2의&amp;nbsp;벡터:&amp;nbsp;`[0.1,&amp;nbsp;0.7,&amp;nbsp;0.0,&amp;nbsp;0.4]`&lt;br /&gt;&lt;br /&gt;1. 내적 계산 (\( A \cdot B \)):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\[&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(0.5&amp;nbsp;\times&amp;nbsp;0.1)&amp;nbsp;+&amp;nbsp;(0.3&amp;nbsp;\times&amp;nbsp;0.7)&amp;nbsp;+&amp;nbsp;(0.0&amp;nbsp;\times&amp;nbsp;0.0)&amp;nbsp;+&amp;nbsp;(0.2&amp;nbsp;\times&amp;nbsp;0.4)&amp;nbsp;=&amp;nbsp;0.05&amp;nbsp;+&amp;nbsp;0.21&amp;nbsp;+&amp;nbsp;0&amp;nbsp;+&amp;nbsp;0.08&amp;nbsp;=&amp;nbsp;0.34&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\]&lt;br /&gt;&lt;br /&gt;2. 벡터의 크기 계산 (\( \|A\| \)와 \( \|B\| \)):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\[&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\|A\|&amp;nbsp;=&amp;nbsp;\sqrt {0.5^2&amp;nbsp;+&amp;nbsp;0.3^2&amp;nbsp;+&amp;nbsp;0.0^2&amp;nbsp;+&amp;nbsp;0.2^2}&amp;nbsp;=&amp;nbsp;\sqrt {0.25&amp;nbsp;+&amp;nbsp;0.09&amp;nbsp;+&amp;nbsp;0&amp;nbsp;+&amp;nbsp;0.04}&amp;nbsp;=&amp;nbsp;\sqrt {0.38}&amp;nbsp;\approx&amp;nbsp;0.616&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\[&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\|B\|&amp;nbsp;=&amp;nbsp;\sqrt {0.1^2&amp;nbsp;+&amp;nbsp;0.7^2&amp;nbsp;+&amp;nbsp;0.0^2&amp;nbsp;+&amp;nbsp;0.4^2}&amp;nbsp;=&amp;nbsp;\sqrt {0.01&amp;nbsp;+&amp;nbsp;0.49&amp;nbsp;+&amp;nbsp;0&amp;nbsp;+&amp;nbsp;0.16}&amp;nbsp;=&amp;nbsp;\sqrt {0.66}&amp;nbsp;\approx&amp;nbsp;0.812&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\]&lt;br /&gt;&lt;br /&gt;3. 코사인 유사도 계산:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\[&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\text {Cosine&amp;nbsp;Similarity}(A,&amp;nbsp;B)&amp;nbsp;=&amp;nbsp;\frac {0.34}{0.616&amp;nbsp;\times&amp;nbsp;0.812}&amp;nbsp;=&amp;nbsp;\frac {0.34}{0.500}&amp;nbsp;\approx&amp;nbsp;0.68&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;\]&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;코사인 유사도 (Cosine Similarity)의 장단점&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 코사인 유사도는 벡터의 크기(길이)가 아닌 &lt;b&gt;방향&lt;/b&gt;에 초점을 맞춰 두 벡터 간의 유사도를 측정하기 때문에 텍스트 데이터에서 &lt;b&gt;문서의 길이와 무관하게 내용의 유사성&lt;/b&gt;을 평가할 수 있어, 문서 분류, 추천 시스템 등에 효과적입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 희소 행렬(Sparse Matrix)에서 &lt;b&gt;0이 많은 경우에도&lt;/b&gt; 유사도를 측정하는 데 있어 &lt;b&gt;유클리드 거리보다&lt;/b&gt; 더 &lt;b&gt;정확한 결과&lt;/b&gt;를 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;- &lt;/span&gt;코사인 유사도는 벡터의 방향만 고려하므로, 벡터의 크기에 영향을 받지 않습니다. 따라서 &lt;b&gt;정규화 과정 없이&lt;/b&gt; 바로 유사도를 계산할 수 있어 &lt;b&gt;계산 비용을 줄일 수 있습니다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 추천 시스템, 문서 검색, 클러스터링 등에서 문서 간의 &lt;b&gt;내용 유사성&lt;/b&gt;을 평가할 때 자주 사용됩니다. 특히 &lt;b&gt;텍스트 데이터&lt;/b&gt;와 같이 벡터의 크기보다는 &lt;b&gt;단어의 조합과 빈도가 중요한 경우&lt;/b&gt;에 유리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 코사인 유사도는 단순히 &lt;b&gt;단어의 빈도와 중요도&lt;/b&gt;만을 사용하여 벡터를 비교하기 때문에, &lt;b&gt;단어 간의 문맥적 관계&lt;/b&gt;를 고려하지 못합니다. 예를 들어, &lt;b&gt;동의어나 유사한 의미를 가진 단어&lt;/b&gt;가 다른 벡터로 표현되면, 문서의 의미가 유사하더라도 낮은 유사도 값을 가질 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;예를 들어, &quot;car&quot;와 &quot;vehicle&quot;이 동의어이더라도, &quot;car&quot;가 한 문서에서 자주 등장해 TF-IDF 값이 낮고, &quot;vehicle&quot;이 다른 문서에서 드물게 등장해 TF-IDF 값이 높다면, 두 벡터는 다른 방향을 가질 수 있습니다. 이로 인해 코사인 유사도 값이 낮게 나오게 되는 거죠. &lt;b&gt;이를 해결하기 위해 Word2Vec, BERT와 같은 임베딩 기법을 활용하면 단어 간의 문맥을 반영하여 더 정확한 유사도 측정이 가능합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 희소 행렬에서 공통으로 등장하는 단어가 거의 없는 경우, 대부분의 값이 0이 됩니다. 예를 들어, 'car'라는 단어가 &lt;b&gt;문서 1에만 1번 등장&lt;/b&gt;하고 다른 문서에는 전혀 등장하지 않는다면, &lt;b&gt;다른 문서에서는 해당 단어의 값이 모두 0&lt;/b&gt;이 됩니다. 이로 인해 문서 간 유사도를 비교할 때 코사인 유사도가 낮게 나올 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- &lt;b&gt;단어의 순서를 무시&lt;/b&gt;하고 벡터화된 단어 빈도만을 사용하기 때문에 &lt;b&gt;문장의 구조나 문맥&lt;/b&gt;을 반영하지 못해, 같은 단어들이 포함되어 있어도 &lt;b&gt;다른 의미를 가질 수 있는 문장들&lt;/b&gt;을 구분하지 못합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;결론적으로, &lt;i&gt;&lt;u&gt;코사인 유사도는&amp;nbsp;&lt;/u&gt;&lt;/i&gt;&lt;/b&gt;&lt;i&gt;&lt;u&gt;텍스트 데이터에서 &lt;b&gt;문서의 길이에 영향을 받지 않고&lt;/b&gt; 유사도를 측정할 수 있어, 추천 시스템과 텍스트 분류 등에 매우 적합하지만, &lt;b&gt;단어의 순서나 문맥&lt;/b&gt;을 고려하지 않기 때문에, &lt;b&gt;더 깊은 의미를 이해하는 데 한계&lt;/b&gt;가 있습니다.&lt;/u&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;따라서 &lt;b&gt;코사인 유사도는 텍스트 데이터에서 주로 사용&lt;/b&gt;되지만, 더 높은 수준의 이해가 필요한 분석에서는 &lt;b&gt;Word2Vec, BERT&lt;/b&gt;와 같은 &lt;b&gt;임베딩 기법&lt;/b&gt;을 사용할 수도 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;b&gt;코사인 유사도를 이용한 텍스트 문서 유사도 분석 (예제)&lt;/b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;우리가 앞서 학습한 TF-IDF를 이용해 문서를 벡터로 변환한 후, 코사인 유사도를 통해 문서 간 유사도를 측정해 보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1731513302643&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import pandas as pd

# 예제 문서 리스트
corpus = [
    &quot;나는 오늘 밥을 먹었다&quot;,
    &quot;밥을 먹고 운동을 했다&quot;,
    &quot;오늘 운동을 마치고 밥을 먹었다&quot;
]

# TF-IDF 벡터화
vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform(corpus)

# 코사인 유사도 계산
cosine_sim = cosine_similarity(tfidf_matrix, tfidf_matrix)

# 결과를 데이터프레임으로 보기 좋게 출력
df = pd.DataFrame(cosine_sim, index=[&quot;문서1&quot;, &quot;문서2&quot;, &quot;문서3&quot;], columns=[&quot;문서1&quot;, &quot;문서2&quot;, &quot;문서3&quot;])
print(&quot;코사인 유사도 행렬:&quot;)
print(df)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;192&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1sZ1f/btsKH0VcVaV/oUPt2lOsdDLHwnSrotYFRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1sZ1f/btsKH0VcVaV/oUPt2lOsdDLHwnSrotYFRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1sZ1f/btsKH0VcVaV/oUPt2lOsdDLHwnSrotYFRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1sZ1f%2FbtsKH0VcVaV%2FoUPt2lOsdDLHwnSrotYFRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;538&quot; height=&quot;180&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;192&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;문서 1, 2, 3의 코사인 유사도 결과를 보면,&lt;br /&gt;문서 1과 문서 3의 유사도가 0.552로 가장 높습니다. 이는 두 문서에 &lt;b&gt;유사한 단어가 많이 포함&lt;/b&gt;되어 있다는 것을 의미합니다.&lt;br /&gt;또한 문서 2와 다른 문서들 간의 유사도는 상대적으로 낮습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;코사인 유사도를 이용한 영화 추천 시스템 (실습)&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;추천 시스템이란?&lt;br /&gt;- 추천 시스템은 사용자의 취향을 분석하여 관련된 콘텐츠(예: 영화, 음악, 도서)를 추천하는 시스템입니다.&lt;br /&gt;- 콘텐츠 기반 추천과 협업 필터링 추천 방식이 대표적입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이제 코사인 유사도를 활용하여,&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #24292f; text-align: start;&quot;&gt;좋아하는 영화를 &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #24292f; text-align: start;&quot;&gt;입력하면&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #24292f; text-align: start;&quot;&gt; 해당 영화의 줄거리와 유사한 줄거리의 영화를 찾아서 추천하는&lt;/span&gt;&lt;/b&gt; 코드를 작성해 보도록 해요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;우선 사용할 데이터셋을 불러옵니다.&lt;/p&gt;
&lt;pre id=&quot;code_1731514570321&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import pandas as pd

# 인코딩을 'ISO-8859-1'로 지정하여 파일 로드
movies_df = pd.read_csv('movies_metadata_low.csv', encoding='ISO-8859-1')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;`movies_metadata_low.csv` 파일에는 24개의 열(column)과 45466개의 행(row)이 포함되어 있습니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;사용할 칼럼만 불러와서 확인해 볼게요.&lt;/p&gt;
&lt;pre id=&quot;code_1731514819842&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;movies_df[['title','overview']]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;874&quot; data-origin-height=&quot;494&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YZqDK/btsKHadngCY/l6bQBTg1v50JXaRDRkMzwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YZqDK/btsKHadngCY/l6bQBTg1v50JXaRDRkMzwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YZqDK/btsKHadngCY/l6bQBTg1v50JXaRDRkMzwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYZqDK%2FbtsKHadngCY%2Fl6bQBTg1v50JXaRDRkMzwK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;582&quot; height=&quot;329&quot; data-origin-width=&quot;874&quot; data-origin-height=&quot;494&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;title과 overview 칼럼에는 결측값이 존재하네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;이제 `overview`(줄거리 설명)을 활용해, &lt;b&gt;영화 간 유사도&lt;/b&gt;를 측정하고 &lt;b&gt;추천 시스템&lt;/b&gt;을 구축할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1️⃣ 데이터 전처리: overview 열에 &lt;b&gt;결측치 처리&lt;/b&gt; 및&lt;b&gt; 텍스트 전처리&lt;/b&gt;를 합니다.&lt;/h4&gt;
&lt;pre id=&quot;code_1731515160684&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

# Step 1: 결측치 처리 (overview 열에서 결측값을 빈 문자열로 대체)
movies_df['overview'] = movies_df['overview'].fillna('')&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;874&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/K7uSi/btsKIPk7a5I/zW1nHpKKD8koS6yTcmiKw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/K7uSi/btsKIPk7a5I/zW1nHpKKD8koS6yTcmiKw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/K7uSi/btsKIPk7a5I/zW1nHpKKD8koS6yTcmiKw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK7uSi%2FbtsKIPk7a5I%2FzW1nHpKKD8koS6yTcmiKw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;585&quot; height=&quot;340&quot; data-origin-width=&quot;874&quot; data-origin-height=&quot;508&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;2️⃣ TF-IDF 벡터화: overview 텍스트를 &lt;b&gt;TF-IDF 벡터화&lt;/b&gt;하여 문서를 수치화합니다.&lt;/h4&gt;
&lt;pre id=&quot;code_1731515254689&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Step 2: TF-IDF 벡터화 (overview 텍스트를 수치화)
tfidf_vectorizer = TfidfVectorizer(stop_words='english')
tfidf_matrix = tfidf_vectorizer.fit_transform(movies_df['overview'])

# TF-IDF 행렬을 Pandas DataFrame으로 변환
tfidf_df = pd.DataFrame(tfidf_matrix.toarray(), columns=tfidf_vectorizer.get_feature_names_out())
print(tfidf_df)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;824&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GIhdU/btsKHvBrrnO/OawfgWlDXK5mctOrSngTNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GIhdU/btsKHvBrrnO/OawfgWlDXK5mctOrSngTNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GIhdU/btsKHvBrrnO/OawfgWlDXK5mctOrSngTNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGIhdU%2FbtsKHvBrrnO%2FOawfgWlDXK5mctOrSngTNK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;576&quot; height=&quot;499&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;824&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;TF-IDF 벡터화한 결과를 보면 총 45466개의 행(row)과 19741개의 열(column)이 출력되었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이는 45466개의 영화가 있으며, 19741개의 고유한 단어들을 나타냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3️⃣ 코사인 유사도 계산: 영화 줄거리 간의 &lt;b&gt;코사인 유사도&lt;/b&gt;를 계산하여, 특정 영화와 유사한 영화를 찾습니다.&lt;/h4&gt;
&lt;pre id=&quot;code_1731515980521&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Step 3: 코사인 유사도 계산 (모든 영화 간의 유사도)
cosine_sim = cosine_similarity(tfidf_matrix, tfidf_matrix)
print('코사인 유사도 연산 결과 :',cosine_sim.shape)

&amp;gt; 코사인 유사도 연산 결과 : (45466, 45466)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;코사인 유사도 연산 결과로 생성된 행렬은 45466개의 행과 열을 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이는 45466개의 각 문서 벡터(영화 줄거리 벡터)와 자기 자신을 포함한 다른 45466개의 문서 벡터 간의 유사도를 기록한 행렬입니다. 이 행렬에는 모든 영화 간의 상호 유사도가 기록되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이제 기존 데이터프레임으로부터 &lt;b&gt;영화의 타이틀을 key&lt;/b&gt;, &lt;b&gt;영화의 인덱스를 value&lt;/b&gt;로 하는 딕셔너리 movie_indices를 만들어둡니다.&lt;/p&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #f5f5f5; color: #333333; text-align: start;&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# 영화 제목을 키(key)로, 데이터프레임의 인덱스를 값(value)으로 갖는 딕셔너리 생성
movie_indices = dict(zip(movies_df['title'], movies_df.index))
movie_indices

&amp;gt; {'Toy Story': 0,
 'Jumanji': 1,
 'Grumpier Old Men': 2,
 'Waiting to Exhale': 3,
 'Father of the Bride Part II': 4,
 'Heat': 5,
 'Sabrina': 888,
 'Tom and Huck': 7,
 'Sudden Death': 8,
 'GoldenEye': 9,
 'The American President': 10,
 'Dracula: Dead and Loving It': 11,
 'Balto': 12,
 'Nixon': 13,
 'Cutthroat Island': 14,
 'Casino': 15,
 'Sense and Sensibility': 16,
 'Four Rooms': 17,
 'Ace Ventura: When Nature Calls': 18,
 'Money Train': 19,
 'Get Shorty': 20,
 'Copycat': 21,
 'Assassins': 22,
 'Powder': 23,
 'Leaving Las Vegas': 24,
...
 'Robin Hood: Prince of Thieves': 998,
 'Mary Poppins': 999,
 'Dumbo': 1000,
 &quot;Pete's Dragon&quot;: 1001,
 ...}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;4️⃣ 추천 시스템 구현: 영화의 제목을 입력하면 사용자가 선택한 영화와 &lt;b&gt;가장 유사한 영화 5개를 추천&lt;/b&gt;합니다.&lt;/h4&gt;
&lt;pre id=&quot;code_1731517108671&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 코사인 유사도를 기반으로 영화 추천 함수 정의
def get_recommendations(title, cosine_sim=cosine_sim):
    # 선택한 영화의 인덱스 가져오기
    idx = movie_indices.get(title) # 주어진 영화 제목(title)에 해당하는 인덱스(idx) 값을 반환합니다. ex) 485
    if idx is None:
        return &quot;해당 영화 제목이 데이터에 없습니다.&quot;
    
    # 해당 영화와 다른 영화 간의 유사도 점수 추출
    sim_scores = list(enumerate(cosine_sim[idx])) # (영화 인덱스, 유사도 점수) -&amp;gt; [(0, 0.143), (1, 0.0)...]

    # 유사도 점수를 기준으로 정렬 (내림차순)
    sim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True)
    
    # 가장 유사한 영화 5개 선택 (자기 자신 제외)
    sim_scores = sim_scores[1:6] # [(0, 0.14393405169022885), (959, 0.13863297484628673), (2371, 0.13518346539986825), (3201, 0.12138975288943879), (2845, 0.1172780131667607)]

    # 추천 영화 목록 출력
    recommended_indices = [i[0] for i in sim_scores] # 영화 인덱스
    recommended_titles = movies_df['title'].iloc[recommended_indices] # 영화 제목
    return recommended_titles.tolist()

# 예시: 'Malice'와 유사한 영화 추천
get_recommendations(&quot;Malice&quot;)

&amp;gt; ['Toy Story', 'Bliss', 'Tinseltown', 'Judy Berlin', 'The Story of Us']&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;유클리드 거리 (Euclidean Distance)란?&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;유클리드 거리는 &lt;b&gt;두 벡터 간의 직선거리를&lt;/b&gt; 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;값이 작을수록 두 문서가 더 유사&lt;/b&gt;하다는 의미이며, 반대로 &lt;b&gt;값이 클수록 문서 간의 차이가 크다&lt;/b&gt;는 의미입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;주로&amp;nbsp;좌표 공간에서 &lt;b&gt;두 점 사이의 거리&lt;/b&gt;를 구할 때 사용됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;\[&lt;br /&gt;\text {Euclidean&amp;nbsp;Distance}(A,&amp;nbsp;B)&amp;nbsp;=&amp;nbsp;\sqrt {\sum_{i=1}^{n}&amp;nbsp;(A_i&amp;nbsp;-&amp;nbsp;B_i)^2}&lt;br /&gt;\]&lt;br /&gt;&lt;br /&gt;-&amp;nbsp;\(&amp;nbsp;A&amp;nbsp;\)와&amp;nbsp;\(&amp;nbsp;B&amp;nbsp;\):&amp;nbsp;두&amp;nbsp;벡터&lt;br /&gt;-&amp;nbsp;\(&amp;nbsp;n&amp;nbsp;\):&amp;nbsp;벡터의&amp;nbsp;차원&amp;nbsp;수&lt;br /&gt;-&amp;nbsp;\(&amp;nbsp;A_i,&amp;nbsp;B_i&amp;nbsp;\):&amp;nbsp;두&amp;nbsp;벡터의&amp;nbsp;각&amp;nbsp;성분&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&lt;b&gt;TF-IDF 벡터화&lt;/b&gt;를 통해 각 문서는 &lt;b&gt;수치화된 벡터&lt;/b&gt;로 변환됩니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;각 벡터는 &lt;b&gt;단어의 중요도&lt;/b&gt;를 반영한 값들로 구성되어 있으며, 단어마다 다른 &lt;b&gt;TF-IDF 점수&lt;/b&gt;를 가집니다.&lt;br /&gt;예를 들어, 두 문서가 비슷한 내용을 가지고 있다면, 이 두 문서의 TF-IDF 벡터는 &lt;b&gt;비슷한 값들을&lt;/b&gt; 갖게 되죠.&lt;br /&gt;&lt;br /&gt;거리 계산은 다음과 같이 이루어지는데요.&lt;br /&gt;&amp;nbsp;&amp;nbsp;\[&lt;br /&gt;&amp;nbsp;&amp;nbsp;\text {Euclidean&amp;nbsp;Distance}(A,&amp;nbsp;B)&amp;nbsp;=&amp;nbsp;\sqrt {\sum_{i=1}^{n}&amp;nbsp;(A_i&amp;nbsp;-&amp;nbsp;B_i)^2}&lt;br /&gt;&amp;nbsp;&amp;nbsp;\]&lt;br /&gt;여기서 \(A_i\)와 \(B_i\)는 두 문서의&amp;nbsp;&lt;b&gt;TF-IDF&amp;nbsp;벡터에서&amp;nbsp;각&amp;nbsp;단어의&amp;nbsp;중요도&lt;/b&gt;를&amp;nbsp;나타내는&amp;nbsp;값입니다.&lt;br /&gt;&lt;b&gt;TF-IDF 값이 비슷한 문서&lt;/b&gt;들은, 위 식에서 각 성분의 차이 \((A_i - B_i)\)가 작아지므로, &lt;b&gt;유클리드 거리 값이 작게&lt;/b&gt; 나오겠죠.&lt;br /&gt;&lt;br /&gt;만약, 아래와 같은 3개의 문서가 있는 경우&lt;br /&gt;-&amp;nbsp;문서&amp;nbsp;A:&amp;nbsp;&quot;고양이가&amp;nbsp;귀엽다&quot;&lt;br /&gt;-&amp;nbsp;문서&amp;nbsp;B:&amp;nbsp;&quot;고양이가&amp;nbsp;매우&amp;nbsp;귀엽다&quot;&lt;br /&gt;-&amp;nbsp;문서&amp;nbsp;C:&amp;nbsp;&quot;자동차를&amp;nbsp;운전하다&quot;&lt;br /&gt;&lt;br /&gt;TF-IDF로 벡터화하면 문서 A와 B는 비슷한 단어를 사용하므로 &lt;b&gt;유사한 벡터&lt;/b&gt;를 가질 것입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;반면, 문서 C는 전혀 다른 단어를 사용하므로 &lt;b&gt;벡터가 다를 것&lt;/b&gt;입니다.&lt;br /&gt;&lt;br /&gt;결국 유클리드 거리 계산 결과는,&lt;br /&gt;A와 B 간의 거리는 &lt;b&gt;짧고&lt;/b&gt; (비슷한 문서)&lt;br /&gt;A와 C 또는 B와 C 간의 거리는 &lt;b&gt;길어집니다.&lt;/b&gt; (내용이 다른 문서)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;텍스트 데이터에서 유클리드 거리를 어떻게 계산할까?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;예를 들어, 세 개의 문서에 대해 TF-IDF를 계산했다고 가정해 보겠습니다.&lt;br /&gt;&lt;br /&gt;1.&amp;nbsp;문서&amp;nbsp;1의&amp;nbsp;TF-IDF&amp;nbsp;결과:&amp;nbsp;`[0.5,&amp;nbsp;0.3,&amp;nbsp;0.0,&amp;nbsp;0.2]`&lt;br /&gt;2.&amp;nbsp;문서&amp;nbsp;2의&amp;nbsp;TF-IDF&amp;nbsp;결과:&amp;nbsp;`[0.1,&amp;nbsp;0.7,&amp;nbsp;0.0,&amp;nbsp;0.4]`&lt;br /&gt;3.&amp;nbsp;문서&amp;nbsp;3의&amp;nbsp;TF-IDF&amp;nbsp;결과:&amp;nbsp;`[0.0,&amp;nbsp;0.2,&amp;nbsp;0.6,&amp;nbsp;0.1]`&lt;br /&gt;&lt;br /&gt;TF-IDF 벡터를 사용해 유클리드 거리를 계산하는 과정은 다음과 같습니다.&lt;br /&gt;&lt;br /&gt;\[&lt;br /&gt;\text{Euclidean&amp;nbsp;Distance}(A,&amp;nbsp;B)&amp;nbsp;=&amp;nbsp;\sqrt{\sum_{i=1}^{n}&amp;nbsp;(A_i&amp;nbsp;-&amp;nbsp;B_i)^2}&lt;br /&gt;\]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;만약, 문서 1과 문서 2의 유클리드 거리를 계산한다면&lt;br /&gt;-&amp;nbsp;문서&amp;nbsp;1의&amp;nbsp;벡터:&amp;nbsp;`[0.5,&amp;nbsp;0.3,&amp;nbsp;0.0,&amp;nbsp;0.2]`&lt;br /&gt;-&amp;nbsp;문서&amp;nbsp;2의&amp;nbsp;벡터:&amp;nbsp;`[0.1,&amp;nbsp;0.7,&amp;nbsp;0.0,&amp;nbsp;0.4]`&lt;br /&gt;&lt;br /&gt;1. 벡터 성분 간의 차이 계산&lt;br /&gt;\[&lt;br /&gt;(0.5&amp;nbsp;-&amp;nbsp;0.1)^2&amp;nbsp;=&amp;nbsp;0.16&lt;br /&gt;\]&lt;br /&gt;\[&lt;br /&gt;(0.3&amp;nbsp;-&amp;nbsp;0.7)^2&amp;nbsp;=&amp;nbsp;0.16&lt;br /&gt;\]&lt;br /&gt;\[&lt;br /&gt;(0.0&amp;nbsp;-&amp;nbsp;0.0)^2&amp;nbsp;=&amp;nbsp;0&lt;br /&gt;\]&lt;br /&gt;\[&lt;br /&gt;(0.2&amp;nbsp;-&amp;nbsp;0.4)^2&amp;nbsp;=&amp;nbsp;0.04&lt;br /&gt;\]&lt;br /&gt;&lt;br /&gt;2. 차이 제곱합 계산&lt;br /&gt;\[&lt;br /&gt;0.16&amp;nbsp;+&amp;nbsp;0.16&amp;nbsp;+&amp;nbsp;0&amp;nbsp;+&amp;nbsp;0.04&amp;nbsp;=&amp;nbsp;0.36&lt;br /&gt;\]&lt;br /&gt;&lt;br /&gt;####&amp;nbsp;3.&amp;nbsp;제곱근&amp;nbsp;계산&lt;br /&gt;\[&lt;br /&gt;\sqrt {0.36}&amp;nbsp;=&amp;nbsp;0.6&lt;br /&gt;\]&lt;br /&gt;&lt;br /&gt;따라서, 문서 1과 문서 2의 유클리드 거리는 0.6입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;유클리드 거리 (Euclidean Distance)의 장단점&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- &lt;b&gt;두 벡터 간의 직선거리를&lt;/b&gt; 측정하기 때문에 개념적으로 매우 직관적입니다. 좌표 공간에서 두 점 사이의 거리와 동일한 방식으로 계산되므로, 수치화된 데이터를 분석할 때 쉽게 적용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- &lt;b&gt;수치형 데이터&lt;/b&gt;나 &lt;b&gt;좌표 공간에서의 거리 측정&lt;/b&gt;에 적합합니다. 예를 들어, 고객의 위치, 제품의 특징 벡터 등 수치형 데이터를 다룰 때 유용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 벡터의 각 성분 간 차이를 고려하기 때문에, 데이터 간의 &lt;b&gt;절대적인 차이&lt;/b&gt;를 반영하는 데 유리합니다. 이로 인해 &lt;b&gt;벡터의 크기가 중요한 분석&lt;/b&gt;에서 유클리드 거리가 효과적입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 텍스트 데이터의 경우, 유클리드 거리는 &lt;b&gt;벡터의 크기에 영향을 받습니다&lt;/b&gt;. 즉, 문서가 길어지면 해당 벡터의 크기도 커지므로, 두 문서 간의 거리가 실제 유사성과 관계없이 멀어질 수 있습니다. 따라서 &lt;b&gt;문서 길이가 다를 경우&lt;/b&gt;, 유클리드 거리는 왜곡된 결과를 초래할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- &lt;b&gt;데이터의 스케일&lt;/b&gt;에 매우 민감합니다. 데이터의 범위가 다를 경우, 큰 값이 작은 값보다 더 큰 영향을 미치게 되므로,&lt;b&gt; 데이터를 스케일링(정규화) 하지&lt;/b&gt; 않으면 부정확한 결과를 가져올 수 있습니다. (TfidfVectorizer는 정규화를 포함하고 있어서 적용하지 않아도 됨)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 텍스트 데이터를 TF-IDF로 변환하면, 보통 &lt;b&gt;희소 행렬(Sparse Matrix)&lt;/b&gt; 형태로 나타나게 됩니다. 희소 행렬에서 &lt;b&gt;0이 많은 경우&lt;/b&gt;, 벡터 성분 간의 차이 값이 커질 수 있어 &lt;b&gt;왜곡된 거리&lt;/b&gt;를 초래할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 유클리드 거리는 &lt;b&gt;벡터의 크기 차이만을 반영&lt;/b&gt;하기 때문에 텍스트 데이터처럼 벡터의 &lt;b&gt;방향(내용의 유사성)이 중요한 경우&lt;/b&gt;에는 부적합할 수 있습니다. 예를 들어, &lt;b&gt;문서의 길이가 다르지만 내용이 유사한 문서&lt;/b&gt;들 간의 유사도를 정확히 평가하기 어렵습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;유클리드 거리를 이용한 텍스트 문서 유사도 분석 (예제)&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;TF-IDF로 벡터화한 문서 데이터를 활용해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;유클리드 거리&lt;/b&gt;를 계산하고, 문서 간 유사도를 측정해 보겠습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1️⃣ 예제 데이터 준비&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1731566393078&quot; class=&quot;nix&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;from sklearn.feature_extraction.text import TfidfVectorizer
import pandas as pd
from scipy.spatial.distance import euclidean

# 예제 문서 리스트
corpus = [
    &quot;나는 오늘 밥을 먹었다&quot;,
    &quot;밥을 먹고 운동을 했다&quot;,
    &quot;오늘 운동을 마치고 밥을 먹었다&quot;
]

# TF-IDF 벡터화
vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform(corpus).toarray()

# 문서 간 유클리드 거리 계산
def calculate_euclidean_distance(matrix):
    n = matrix.shape[0] # 문서의 개수
    distances = pd.DataFrame(index=range(n), columns=range(n)) # n x n 크기의 빈 데이터프레임 생성
    # 문서 간 유클리드 거리 계산
    for i in range(n):
        for j in range(n):
            distances.iloc[i, j] = euclidean(matrix[i], matrix[j])
    return distances

# 유클리드 거리 행렬 출력
euclidean_distances = calculate_euclidean_distance(tfidf_matrix)
euclidean_distances.index = [&quot;문서1&quot;, &quot;문서2&quot;, &quot;문서3&quot;]
euclidean_distances.columns = [&quot;문서1&quot;, &quot;문서2&quot;, &quot;문서3&quot;]
print(&quot;\n유클리드 거리 행렬:&quot;)
print(euclidean_distances)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;570&quot; data-origin-height=&quot;174&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mfrTf/btsKJjtqtyM/q2UuY4T4rHAW5ylK9WE6Hk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mfrTf/btsKJjtqtyM/q2UuY4T4rHAW5ylK9WE6Hk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mfrTf/btsKJjtqtyM/q2UuY4T4rHAW5ylK9WE6Hk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmfrTf%2FbtsKJjtqtyM%2Fq2UuY4T4rHAW5ylK9WE6Hk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;570&quot; height=&quot;174&quot; data-origin-width=&quot;570&quot; data-origin-height=&quot;174&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;문서 1, 2, 3의 유클리드 거리 결과를 보면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;1.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;문서 1과 문서 3의&lt;/b&gt; 유클리드 거리가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;0.96&lt;/b&gt;으로 가장 가깝습니다. 즉, 이 두 문서는 서로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;가장 유사한 내용&lt;/b&gt;을 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;2.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;문서 1과 문서 2의&lt;/b&gt; 거리는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;1.32&lt;/b&gt;로, 서로 더&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;멀리 떨어져&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;있어 덜 유사합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;3.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;문서 2와 문서 3의&lt;/b&gt; 거리는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;1.18&lt;/b&gt;입니다. 이 값은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;문서 1과 문서 2의&lt;/b&gt; 거리보다는 가깝지만,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;문서 1과 문서 3만큼&lt;/b&gt; 가깝지는 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;자기 자신과의 거리는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;항상 0&lt;/b&gt;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;결론적으로&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;문서1&lt;/b&gt;과&amp;nbsp;&lt;b&gt;문서 3이&lt;/b&gt;&lt;/span&gt; 가장 유사하며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;b&gt;문서1&lt;/b&gt;과&lt;/span&gt;&amp;nbsp;&lt;b&gt;문서 2는&lt;/b&gt;&lt;/span&gt; 가장 덜 유사합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;유클리드 거리를 이용한 영화 추천 시스템 (실습)&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;이제&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;영화 데이터셋&lt;/b&gt;을 활용하여, 영화 줄거리(&lt;span&gt;overview&lt;/span&gt;)를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;유클리드 거리&lt;/b&gt;로 비교해 유사한 영화를 추천하는 시스템을 구축해 보겠습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1️⃣ 데이터 준비 및 전처리&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;전처리까지는 위에서 진행한 코사인 유사도와 동일한 코드입니다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1731566393081&quot; class=&quot;clean&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from scipy.spatial.distance import euclidean

# 데이터 로드 및 전처리
movies_df = pd.read_csv('movies_metadata_low.csv', encoding='ISO-8859-1')
movies_df['overview'] = movies_df['overview'].fillna('')

# TF-IDF 벡터화
tfidf_vectorizer = TfidfVectorizer(stop_words='english')
tfidf_matrix = tfidf_vectorizer.fit_transform(movies_df['overview']).toarray()

# 영화 제목과 인덱스를 매핑하는 딕셔너리 생성
movie_indices = dict(zip(movies_df['title'], movies_df.index))&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2️⃣ 유클리드 거리 기반 추천 함수 구현&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1731566393082&quot; class=&quot;python&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;def get_recommendations_euclidean(title, n_recommendations=5):
    # 선택한 영화의 인덱스 가져오기
    idx = movie_indices.get(title)
    if idx is None:
        return &quot;해당 영화 제목이 데이터에 없습니다.&quot;
    
    # 선택한 영화의 TF-IDF 벡터
    target_vector = tfidf_matrix[idx]
    
    # 모든 영화와의 유클리드 거리 계산
    distances = []
    for i in range(len(tfidf_matrix)):
        # 선택된 영화(target_vector)와 모든 영화 간의 유클리드 거리를 계산
        dist = euclidean(target_vector, tfidf_matrix[i])
        distances.append((i, dist))
    
    # 거리 기준으로 정렬 (가까운 순)
    distances = sorted(distances, key=lambda x: x[1])
    
    # 가장 가까운 영화 n개 선택 (자기 자신 제외)
    recommended_indices = [i[0] for i in distances[1:n_recommendations + 1]]
    recommended_titles = movies_df['title'].iloc[recommended_indices]
    return recommended_titles.tolist()

# 예시: 'Malice'와 유사한 영화 추천
print(get_recommendations_euclidean(&quot;Malice&quot;))

&amp;gt; ['Wings of Courage', 'Roommates', 'Peanuts  Die Bank zahlt alles', 'Happy Weekend', 'The Superwife']&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;자카드&amp;nbsp;유사도(Jaccard&amp;nbsp;Similarity)란?&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;자카드 유사도는 두 집합 간의 유사도를 측정하는 지표로, 두 집합의 교집합 크기를 합집합 크기로 나눈 값으로 정의됩니다.&lt;br /&gt;&lt;br /&gt;\[&lt;br /&gt;\text {Jaccard&amp;nbsp;Similarity}(A,&amp;nbsp;B)&amp;nbsp;=&amp;nbsp;\frac {|A&amp;nbsp;\cap&amp;nbsp;B|}{|A&amp;nbsp;\cup&amp;nbsp;B|}&lt;br /&gt;\]&lt;br /&gt;&lt;br /&gt;-&amp;nbsp;\(A\),&amp;nbsp;\(B\):&amp;nbsp;비교하고자&amp;nbsp;하는&amp;nbsp;두&amp;nbsp;개의&amp;nbsp;집합&lt;br /&gt;-&amp;nbsp;\(|A&amp;nbsp;\cap&amp;nbsp;B|\):&amp;nbsp;두&amp;nbsp;집합의&amp;nbsp;교집합&amp;nbsp;크기&lt;br /&gt;-&amp;nbsp;\(|A&amp;nbsp;\cup&amp;nbsp;B|\):&amp;nbsp;두&amp;nbsp;집합의&amp;nbsp;합집합&amp;nbsp;크기&lt;br /&gt;&lt;br /&gt;자카드 유사도 값은 &lt;b&gt;0부터 1 사이&lt;/b&gt;의 값을 가집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;- 1에 가까울수록&lt;/b&gt; 두 집합이 유사함을 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;- 0에 가까울수록&lt;/b&gt; 두 집합이 겹치는 부분이 거의 없음을 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;텍스트 데이터에서 자카드 유사도(Jaccard Similarity)는 어떻게 계산할까?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;아래와 같은 세 개의 문서가 있습니다.&lt;br /&gt;1. 문서 1: &quot;나는 오늘 밥을 먹었다&quot;&lt;br /&gt;2. 문서 2: &quot;밥을 먹고 운동을 했다&quot;&lt;br /&gt;3. 문서 3: &quot;오늘 운동을 마치고 밥을 먹었다&quot;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. 문서의 토큰화 (단어 집합 생성)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;우선, 각 문서를 단어 단위로 분리하여 집합으로 만듭니다.&lt;br /&gt;-&amp;nbsp;문서&amp;nbsp;1의&amp;nbsp;집합:&amp;nbsp;`{나는,&amp;nbsp;오늘,&amp;nbsp;밥을,&amp;nbsp;먹었다}`&lt;br /&gt;-&amp;nbsp;문서&amp;nbsp;2의&amp;nbsp;집합:&amp;nbsp;`{밥을,&amp;nbsp;먹고,&amp;nbsp;운동을,&amp;nbsp;했다}`&lt;br /&gt;-&amp;nbsp;문서&amp;nbsp;3의&amp;nbsp;집합:&amp;nbsp;`{오늘,&amp;nbsp;운동을,&amp;nbsp;마치고,&amp;nbsp;밥을,&amp;nbsp;먹었다}`&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2. 자카드 유사도 계산&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;문서 1과 문서 2의 자카드 유사도&lt;br /&gt;-&amp;nbsp;교집합&amp;nbsp;(\(&amp;nbsp;A&amp;nbsp;\cap&amp;nbsp;B&amp;nbsp;\)):&amp;nbsp;`{밥을}`&lt;br /&gt;-&amp;nbsp;합집합&amp;nbsp;(\(&amp;nbsp;A&amp;nbsp;\cup&amp;nbsp;B&amp;nbsp;\)):&amp;nbsp;`{나는,&amp;nbsp;오늘,&amp;nbsp;밥을,&amp;nbsp;먹었다,&amp;nbsp;먹고,&amp;nbsp;운동을,&amp;nbsp;했다}`&lt;br /&gt;&lt;br /&gt;\[&lt;br /&gt;\text{Jaccard&amp;nbsp;Similarity}(A,&amp;nbsp;B)&amp;nbsp;=&amp;nbsp;\frac{|A&amp;nbsp;\cap&amp;nbsp;B|}{|A&amp;nbsp;\cup&amp;nbsp;B|}&amp;nbsp;=&amp;nbsp;\frac {1}{7}&amp;nbsp;\approx&amp;nbsp;0.143&lt;br /&gt;\]&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;자카드&amp;nbsp;유사도(Jaccard&amp;nbsp;Similarity)의&amp;nbsp;장단점&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;장점&lt;br /&gt;- 집합 간의 유사도를 단순히 교집합과 합집합의 비율로 측정하기 때문에 이해하기 쉽고 계산이 간단합니다.&lt;br /&gt;- &lt;b&gt;단어의 존재 여부&lt;/b&gt;에만 초점을 맞추므로, &lt;b&gt;이진 데이터(존재/부재)&lt;/b&gt;를 분석할 때 유용합니다. 예를 들어, 검색 엔진, 추천 시스템 등에서 주로 사용됩니다.&lt;br /&gt;- 빈도나 가중치 대신 &lt;b&gt;단어의 존재 여부만 고려&lt;/b&gt;하기 때문에, 단어 빈도 차이로 인한 영향이 적고, 노이즈에 강합니다.&lt;br /&gt;&lt;br /&gt;단점&lt;br /&gt;- &lt;b&gt;단어의 빈도나 중요도를 반영하지 않기 때문에&lt;/b&gt;, 문서에서 &lt;b&gt;단어가 얼마나 중요한지&lt;/b&gt;를 고려하지 못합니다. 즉, 단어가 여러 번 등장하더라도 단순히 한 번 존재하는 것과 동일하게 취급됩니다.&lt;br /&gt;- &lt;b&gt;단어의 문맥적 의미&lt;/b&gt;를 반영하지 못합니다. 따라서 &lt;b&gt;동의어나 유사한 의미를 가진 단어&lt;/b&gt;가 포함된 문서들이 실제로는 유사하더라도, 낮은 유사도 값을 가질 수 있습니다. 예를 들어, &quot;car&quot;와 &quot;vehicle&quot;이 각각 다른 문서에 포함된 경우, 자카드 유사도는 두 문서를 낮은 유사도로 평가할 수 있습니다.&lt;br /&gt;- 텍스트 데이터를 자카드 유사도로 비교할 때, &lt;b&gt;공통된 단어가 거의 없는 희소 행렬&lt;/b&gt;에서 유사도가 낮게 나옵니다. 특히, &lt;b&gt;단어가 많고 문서 간에 공통 단어가 적을수록&lt;/b&gt;&amp;nbsp;유사도가 낮아질 수 있어 정확한 유사도 측정이 어려워집니다.&lt;br /&gt;- 단어 수가 매우 적은 짧은 문서 간의 유사도 계산 시, &lt;b&gt;한 단어의 차이로도 유사도 값이 크게 변동&lt;/b&gt;할 수 있습니다.&lt;br /&gt;&lt;br /&gt;결론적으로, 자카드&amp;nbsp;유사도는&amp;nbsp;&lt;b&gt;단어의&amp;nbsp;존재&amp;nbsp;여부&lt;/b&gt;를 기준으로 간단하게 유사도를 측정할 수 있는 방법이지만, &lt;b&gt;단어의 빈도, 중요도, 문맥적 의미&lt;/b&gt;를 반영하지 못합니다. 특히, &lt;b&gt;희소한 데이터나 짧은 문서&lt;/b&gt;를 비교할 때는 신뢰도가 낮아질 수 있습니다. 이러한 이유로, 자카드 유사도는 &lt;b&gt;텍스트 데이터 분석보다는 이진 데이터 분석&lt;/b&gt;에 더 적합한 경우가 많습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;b&gt;자카드 유사도를 이용한 텍스트 문서 유사도 분석 (예제)&lt;/b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1731575254780&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics import jaccard_score

# 예제 문서 리스트
corpus = [
    &quot;나는 오늘 밥을 먹었다&quot;,
    &quot;밥을 먹고 운동을 했다&quot;,
    &quot;오늘 운동을 마치고 밥을 먹었다&quot;
]

# CountVectorizer를 사용해 단어 집합 생성 (1-gram 기준)
vectorizer = CountVectorizer()
binary_matrix = vectorizer.fit_transform(corpus).toarray()

# 자카드 유사도 계산
def calculate_jaccard_similarity(matrix):
    n = matrix.shape[0]
    similarities = []
    for i in range(n):
        for j in range(i + 1, n):
            sim = jaccard_score(matrix[i], matrix[j], average='binary')
            similarities.append((f&quot;문서 {i + 1}&quot;, f&quot;문서 {j + 1}&quot;, sim))
    return similarities

# 결과 출력
jaccard_similarities = calculate_jaccard_similarity(binary_matrix)
for doc1, doc2, sim in jaccard_similarities:
    print(f&quot;{doc1}와 {doc2}의 자카드 유사도: {sim:.3f}&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;504&quot; data-origin-height=&quot;108&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dua4LW/btsKJ2LCP2L/CJR76kNSfcyUiSt2Hn4K20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dua4LW/btsKJ2LCP2L/CJR76kNSfcyUiSt2Hn4K20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dua4LW/btsKJ2LCP2L/CJR76kNSfcyUiSt2Hn4K20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdua4LW%2FbtsKJ2LCP2L%2FCJR76kNSfcyUiSt2Hn4K20%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;443&quot; height=&quot;95&quot; data-origin-width=&quot;504&quot; data-origin-height=&quot;108&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;문서 1과 문서 3의 자카드 유사도(0.500)가 가장 높습니다. 즉, 문서 1과 문서 3이 다른 문서 쌍에 비해 공통된 단어를 더 많이 가지고 있어서 &lt;b&gt;가장 유사한&lt;/b&gt; 것으로 해석할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;b&gt;자카드 유사도&lt;/b&gt;&lt;/b&gt;&lt;b&gt;를 이용한 영화 추천 시스템 (실습)&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;이제&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;영화 데이터셋&lt;/b&gt;을 활용하여, 영화 줄거리(&lt;span&gt;overview&lt;/span&gt;)를&lt;b&gt;&lt;span&gt; 자카드 유사도&lt;/span&gt;&lt;/b&gt;로 비교해 유사한 영화를 추천하는 시스템을 구축해 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-size: 1.12em; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;자카드 유사도를 텍스트 데이터에 적용하려면, 먼저&lt;b&gt; TF-IDF 대신 이진 벡터&lt;/b&gt;를 사용해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;`&lt;b&gt;CountVectorizer&lt;/b&gt;`를 이용해 &lt;b&gt;이진 벡터&lt;/b&gt;로 변환한 후 자카드 유사도를 계산할 수 있습니다.&lt;br /&gt;(CountVectorizer(binary=True)를 사용하여 텍스트를 이진 벡터화합니다. 각 단어가 문서에 &lt;b&gt;존재하면 1, 없으면 0&lt;/b&gt;으로 표시합니다.)&lt;/p&gt;
&lt;pre id=&quot;code_1731575633070&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import pandas as pd
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics import jaccard_score

# 데이터 로드 및 전처리
movies_df = pd.read_csv('movies_metadata_low.csv', encoding='ISO-8859-1')
movies_df['overview'] = movies_df['overview'].fillna('')

# CountVectorizer를 사용해 이진 벡터화
count_vectorizer = CountVectorizer(stop_words='english', binary=True)
binary_matrix = count_vectorizer.fit_transform(movies_df['overview']).toarray()

# 영화 제목과 인덱스를 매핑하는 딕셔너리 생성
movie_indices = dict(zip(movies_df['title'], movies_df.index))

def get_recommendations_jaccard(title, n_recommendations=5):
    # 선택한 영화의 인덱스 가져오기
    idx = movie_indices.get(title)
    if idx is None:
        return &quot;해당 영화 제목이 데이터에 없습니다.&quot;
    
    # 선택한 영화의 이진 벡터 가져오기
    target_vector = binary_matrix[idx]
    
    # 모든 영화와의 자카드 유사도 계산
    similarities = []
    for i in range(len(binary_matrix)):
        sim = jaccard_score(target_vector, binary_matrix[i])
        similarities.append((i, sim))
    
    # 유사도 기준으로 정렬 (내림차순)
    similarities = sorted(similarities, key=lambda x: x[1], reverse=True)
    
    # 가장 유사한 영화 n개 선택 (자기 자신 제외)
    recommended_indices = [i[0] for i in similarities[1:n_recommendations + 1]]
    recommended_titles = movies_df['title'].iloc[recommended_indices]
    return recommended_titles.tolist()

# 'Malice'와 유사한 영화 추천
print(get_recommendations_jaccard(&quot;Malice&quot;))

&amp;gt; ['Bliss', 'The Story of Us', 'Judy Berlin', 'American Graffiti', 'In Dreams']&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>pytorch</category>
      <category>cosine_similarity</category>
      <category>각도</category>
      <category>문서간유사도</category>
      <category>유사도</category>
      <category>유클리드거리</category>
      <category>자카드 유사도</category>
      <category>추천시스템</category>
      <category>코사인유사도</category>
      <category>크기</category>
      <category>텍스트 데이터</category>
      <author>ISFP의 블로그</author>
      <guid isPermaLink="true">https://resultofeffort.tistory.com/147</guid>
      <comments>https://resultofeffort.tistory.com/147#entry147comment</comments>
      <pubDate>Sun, 1 Dec 2024 23:13:18 +0900</pubDate>
    </item>
    <item>
      <title>[오류Error] Resource punkt_tab not found.  Please use the NLTK Downloader to obtain the resource:</title>
      <link>https://resultofeffort.tistory.com/146</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;텍스트 전처리 공부하는 중에 로컬에서 토크나이저를 수행하려고 하니 에러가 발생했다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;sent_text = sent_tokenize(content_text)&lt;/p&gt;
&lt;pre id=&quot;code_1731656276494&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
	&quot;name&quot;: &quot;LookupError&quot;,
	&quot;message&quot;: &quot;
**********************************************************************
  Resource punkt_tab not found.
  Please use the NLTK Downloader to obtain the resource:

  &amp;gt;&amp;gt;&amp;gt; import nltk
  &amp;gt;&amp;gt;&amp;gt; nltk.download('punkt_tab')
  
  For more information see: https://www.nltk.org/data.html

  Attempted to load tokenizers/punkt_tab/english/

  Searched in:
    - '/Users/song/nltk_data'
    - '/Users/song/opt/anaconda3/envs/song38/nltk_data'
    - '/Users/song/opt/anaconda3/envs/song38/share/nltk_data'
    - '/Users/song/opt/anaconda3/envs/song38/lib/nltk_data'
    - '/usr/share/nltk_data'
    - '/usr/local/share/nltk_data'
    - '/usr/lib/nltk_data'
    - '/usr/local/lib/nltk_data'
**********************************************************************
&quot;,
	&quot;stack&quot;: &quot;---------------------------------------------------------------------------
LookupError                               Traceback (most recent call last)
Cell In[8], line 2
      1 # 입력 코퍼스에 대해서 NLTK를 이용하여 문장 토큰화를 수행.
----&amp;gt; 2 sent_text = sent_tokenize(content_text)
      4 # # 각 문장에 대해서 구두점을 제거하고, 대문자를 소문자로 변환.
      5 # normalized_text = []
      6 # for string in sent_text:
   (...)
     10 # # 각 문장에 대해서 NLTK를 이용하여 단어 토큰화를 수행.
     11 # result = [word_tokenize(sentence) for sentence in normalized_text]

File ~/opt/anaconda3/envs/song38/lib/python3.8/site-packages/nltk/tokenize/__init__.py:119, in sent_tokenize(text, language)
    109 def sent_tokenize(text, language=\&quot;english\&quot;):
    110     \&quot;\&quot;\&quot;
    111     Return a sentence-tokenized copy of *text*,
    112     using NLTK's recommended sentence tokenizer
   (...)
    117     :param language: the model name in the Punkt corpus
    118     \&quot;\&quot;\&quot;
--&amp;gt; 119     tokenizer = _get_punkt_tokenizer(language)
    120     return tokenizer.tokenize(text)

File ~/opt/anaconda3/envs/song38/lib/python3.8/site-packages/nltk/tokenize/__init__.py:105, in _get_punkt_tokenizer(language)
     96 @functools.lru_cache
     97 def _get_punkt_tokenizer(language=\&quot;english\&quot;):
     98     \&quot;\&quot;\&quot;
     99     A constructor for the PunktTokenizer that utilizes
    100     a lru cache for performance.
   (...)
    103     :type language: str
    104     \&quot;\&quot;\&quot;
--&amp;gt; 105     return PunktTokenizer(language)

File ~/opt/anaconda3/envs/song38/lib/python3.8/site-packages/nltk/tokenize/punkt.py:1744, in PunktTokenizer.__init__(self, lang)
   1742 def __init__(self, lang=\&quot;english\&quot;):
   1743     PunktSentenceTokenizer.__init__(self)
-&amp;gt; 1744     self.load_lang(lang)

File ~/opt/anaconda3/envs/song38/lib/python3.8/site-packages/nltk/tokenize/punkt.py:1749, in PunktTokenizer.load_lang(self, lang)
   1746 def load_lang(self, lang=\&quot;english\&quot;):
   1747     from nltk.data import find
-&amp;gt; 1749     lang_dir = find(f\&quot;tokenizers/punkt_tab/{lang}/\&quot;)
   1750     self._params = load_punkt_params(lang_dir)
   1751     self._lang = lang

File ~/opt/anaconda3/envs/song38/lib/python3.8/site-packages/nltk/data.py:579, in find(resource_name, paths)
    577 sep = \&quot;*\&quot; * 70
    578 resource_not_found = f\&quot;\
{sep}\
{msg}\
{sep}\
\&quot;
--&amp;gt; 579 raise LookupError(resource_not_found)

LookupError: 
**********************************************************************
  Resource punkt_tab not found.
  Please use the NLTK Downloader to obtain the resource:

  &amp;gt;&amp;gt;&amp;gt; import nltk
  &amp;gt;&amp;gt;&amp;gt; nltk.download('punkt_tab')
  
  For more information see: https://www.nltk.org/data.html

  Attempted to load tokenizers/punkt_tab/english/

  Searched in:
    - '/Users/song/nltk_data'
    - '/Users/song/opt/anaconda3/envs/song38/nltk_data'
    - '/Users/song/opt/anaconda3/envs/song38/share/nltk_data'
    - '/Users/song/opt/anaconda3/envs/song38/lib/nltk_data'
    - '/usr/share/nltk_data'
    - '/usr/local/share/nltk_data'
    - '/usr/lib/nltk_data'
    - '/usr/local/lib/nltk_data'
**********************************************************************
&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;에러 메시지를 보면, &lt;span&gt;nltk&lt;/span&gt; 라이브러리가 &lt;span&gt;punkt_tab&lt;/span&gt; 리소스를 찾지 못해서 발생한 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;punkt&lt;/span&gt;는 NLTK의 &lt;b&gt;문장 토큰화&lt;/b&gt;를 위해 필요한 데이터이기 때문에 &lt;span&gt;nltk.download()&lt;/span&gt; 함수를 사용하여 필요한 데이터를 설치해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;해결 방법&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1731656423627&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import nltk

# punkt 데이터 다운로드
nltk.download('punkt')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>오류Error</category>
      <category>error</category>
      <category>konlpy</category>
      <category>nlp</category>
      <category>nltk</category>
      <category>punkt</category>
      <category>오류</category>
      <category>오블완</category>
      <category>자연어처리</category>
      <category>텍스트전처리</category>
      <category>티스토리챌린지</category>
      <category>해결</category>
      <category>형태소</category>
      <author>ISFP의 블로그</author>
      <guid isPermaLink="true">https://resultofeffort.tistory.com/146</guid>
      <comments>https://resultofeffort.tistory.com/146#entry146comment</comments>
      <pubDate>Fri, 22 Nov 2024 12:24:31 +0900</pubDate>
    </item>
    <item>
      <title>[pytorch] DTM과 TF-IDF | 텍스트 전처리 | 자연어 처리</title>
      <link>https://resultofeffort.tistory.com/145</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;DTM (Document-Term Matrix)이란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;DTM은 &lt;u&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;여러 문서&lt;/b&gt;&lt;/span&gt;&lt;/u&gt;에서 &lt;b&gt;단어의 빈도&lt;/b&gt;를 기록한 행렬(matrix)입니다. BoW와 유사하지만, &lt;b&gt;여러 문서 간의 단어 빈도수를 한꺼번에 분석&lt;/b&gt;할 수 있도록 확장된 형태입니다.&lt;br /&gt;&lt;br /&gt;-&amp;nbsp;행(Row):&amp;nbsp;문서&amp;nbsp;(Document)&lt;br /&gt;-&amp;nbsp;열(Column):&amp;nbsp;단어&amp;nbsp;(Term)&lt;br /&gt;-&amp;nbsp;값(Value):&amp;nbsp;특정&amp;nbsp;문서에&amp;nbsp;특정&amp;nbsp;단어가&amp;nbsp;등장한&amp;nbsp;빈도수&lt;br /&gt;&lt;br /&gt;DTM은&amp;nbsp;m&amp;nbsp;x&amp;nbsp;n&amp;nbsp;형태의&amp;nbsp;행렬로,&amp;nbsp;`m`은&amp;nbsp;문서의&amp;nbsp;개수,&amp;nbsp;`n`은&amp;nbsp;고유&amp;nbsp;단어의&amp;nbsp;개수를&amp;nbsp;의미합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;DTM의 예시&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다음과 같은 예제 문서들을 통해 DTM을 만들어 보겠습니다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;문서 1:&amp;nbsp;&quot;나는&amp;nbsp;오늘&amp;nbsp;밥을&amp;nbsp;먹었다&quot;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;문서 2:&amp;nbsp;&quot;밥을&amp;nbsp;먹고&amp;nbsp;운동을&amp;nbsp;했다&quot;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;문서 3:&amp;nbsp;&quot;오늘&amp;nbsp;운동을&amp;nbsp;마치고&amp;nbsp;밥을&amp;nbsp;먹었다&quot;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1.&amp;nbsp;토큰화(Tokenization)&amp;nbsp;및&amp;nbsp;어휘&amp;nbsp;사전&amp;nbsp;생성&lt;/b&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;모든 문서에서 &lt;b&gt;고유한 단어들을 추출&lt;/b&gt;하여 어휘 사전을 생성합니다.&lt;br /&gt;Vocabulary: ['나는', '오늘', '밥을', '먹었다', '먹고', '운동을', '했다', '마치고']&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2. DTM 생성&amp;nbsp;&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;각 문서에서 &lt;b&gt;단어 빈도를 어휘 사전 순서에 따라 벡터로 변환&lt;/b&gt;합니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 65%; height: 144px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;나는&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;오늘&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;밥을&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;먹었다&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;먹고&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;운동을&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;했다&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;마치고&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;문서 1&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;문서 2&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 19px; text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 11.1111%; height: 10px; text-align: center;&quot;&gt;문서 3&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 10px; text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 10px; text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 10px; text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 10px; text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 10px; text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 10px; text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 10px; text-align: center;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; height: 10px; text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&lt;b&gt;3. Python을 사용한 DTM 구현&lt;/b&gt;&lt;br /&gt;`CountVectorizer`를 사용하면 Python에서 쉽게 DTM을 생성할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1731477095161&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.feature_extraction.text import CountVectorizer
import pandas as pd

# 예제 문서 리스트
corpus = [
    &quot;나는 오늘 밥을 먹었다&quot;,
    &quot;밥을 먹고 운동을 했다&quot;,
    &quot;오늘 운동을 마치고 밥을 먹었다&quot;
]

# CountVectorizer를 사용해 DTM 생성
vectorizer = CountVectorizer()
dtm = vectorizer.fit_transform(corpus)

# DTM을 Pandas DataFrame으로 변환
dtm_df = pd.DataFrame(dtm.toarray(), columns=vectorizer.get_feature_names_out())
print(dtm_df)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;144&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buPdQE/btsKH9KFHQg/jOrzozL07CY9Ijao904tpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buPdQE/btsKH9KFHQg/jOrzozL07CY9Ijao904tpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buPdQE/btsKH9KFHQg/jOrzozL07CY9Ijao904tpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuPdQE%2FbtsKH9KFHQg%2FjOrzozL07CY9Ijao904tpk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;413&quot; height=&quot;84&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;144&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;위에서 작성한 결과와 동일한 결과가 출력되었죠.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;DTM의 장단점&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;장점&lt;br /&gt;-&amp;nbsp;문서를&amp;nbsp;수치화하여&amp;nbsp;머신러닝&amp;nbsp;모델에&amp;nbsp;쉽게&amp;nbsp;활용할&amp;nbsp;수&amp;nbsp;있습니다.&lt;br /&gt;-&amp;nbsp;단순한&amp;nbsp;구현으로&amp;nbsp;빠르게&amp;nbsp;분석을&amp;nbsp;시작할&amp;nbsp;수&amp;nbsp;있습니다.&lt;br /&gt;&lt;br /&gt;단점&lt;br /&gt;-&amp;nbsp;&lt;b&gt;단어의&amp;nbsp;순서&lt;/b&gt;&amp;nbsp;정보가&amp;nbsp;손실됩니다.&lt;br /&gt;-&amp;nbsp;문서가&amp;nbsp;많아질수록&amp;nbsp;&lt;b&gt;희소&amp;nbsp;행렬(Sparse&amp;nbsp;Matrix)&lt;/b&gt;&amp;nbsp;문제가&amp;nbsp;발생합니다.&lt;br /&gt;-&amp;nbsp;어휘&amp;nbsp;사전이&amp;nbsp;클수록&amp;nbsp;&lt;b&gt;메모리&amp;nbsp;사용량&lt;/b&gt;이&amp;nbsp;크게&amp;nbsp;증가합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;DTM의 확장: TF-IDF&amp;nbsp; (Term Frequency-Inverse Document Frequency)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;BoW와 DTM의 단점을 보완하기 위해 TF-IDF (Term Frequency-Inverse Document Frequency)가 자주 사용됩니다. &lt;u&gt;&lt;b&gt;TF-IDF는 단어 빈도뿐만 아니라 문서 내에서의 &lt;span style=&quot;color: #006dd7;&quot;&gt;중요도를 반영&lt;/span&gt;하여 가중치를 조정&lt;/b&gt;&lt;/u&gt;합니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;TF-IDF란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;TF-IDF는 &lt;u&gt;&lt;b&gt;단어 빈도(Term Frequency, TF)&lt;/b&gt;&lt;/u&gt;와 &lt;u&gt;&lt;b&gt;역문서 빈도(Inverse Document Frequency, IDF)&lt;/b&gt;&lt;/u&gt;를 결합하여 각 단어의 &lt;b&gt;중요도를 측정&lt;/b&gt;하는 방법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;BoW와 DTM이 단순히 단어의 빈도만을 고려하는 반면, TF-IDF는 문서 내에서의 빈도뿐만 아니라 &lt;u&gt;&lt;b&gt;해당 단어가 전체 문서에서 얼마나 자주 등장하는지를 고려&lt;/b&gt;&lt;/u&gt;하여 단어의 가중치를 계산합니다.&lt;br /&gt;&lt;br /&gt;TF-IDF는 자주 등장하는 단어(예: &quot;the&quot;, &quot;is&quot;)는 여러 문서에 걸쳐 자주 사용되므로 중요도가 낮다고 판단하고, 특정 문서에서 드물게 등장하는 단어는 해당 문서를 특징짓는 중요한 단어로 간주합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;br /&gt;&lt;b&gt;TF-IDF의 수식&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;TF-IDF는 두 가지 지표를 결합하여 계산합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;1️⃣ Term Frequency (TF)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;TF(Term Frequency)는 특정 단어가 한 문서에서 얼마나 자주 등장하는지를 측정하기 위해 &lt;b&gt;모든 단어에 대해 각 문서에서의 빈도를 계산&lt;/b&gt;합니다.&lt;br /&gt;\[&lt;br /&gt;\text{TF}(t,&amp;nbsp;d)&amp;nbsp;=&amp;nbsp;\frac {\text {단어&amp;nbsp;}&amp;nbsp;t&amp;nbsp;\text {의&amp;nbsp;빈도}}{\text {문서&amp;nbsp;}&amp;nbsp;d&amp;nbsp;\text {의&amp;nbsp;전체&amp;nbsp;단어&amp;nbsp;수}}&lt;br /&gt;\]&lt;br /&gt;&lt;br /&gt;다음과 같은 예제 문서들을 통해 TF를 계산해보겠습니다.&lt;br /&gt;&lt;br /&gt;문서 1:&amp;nbsp;&quot;나는&amp;nbsp;오늘&amp;nbsp;밥을&amp;nbsp;먹었다&quot;&lt;br /&gt;문서 2:&amp;nbsp;&quot;밥을&amp;nbsp;먹고&amp;nbsp;운동을&amp;nbsp;했다&quot;&lt;br /&gt;문서 3:&amp;nbsp;&quot;오늘&amp;nbsp;운동을&amp;nbsp;마치고&amp;nbsp;밥을&amp;nbsp;먹었다&quot;&lt;br /&gt;&lt;br /&gt;우선, 문서에서 고유한 단어들을 추출하여 어휘 사전을 만듭니다.&lt;br /&gt;Vocabulary:&amp;nbsp;['나는',&amp;nbsp;'오늘',&amp;nbsp;'밥을',&amp;nbsp;'먹었다',&amp;nbsp;'먹고',&amp;nbsp;'운동을',&amp;nbsp;'했다',&amp;nbsp;'마치고']&lt;br /&gt;&lt;br /&gt;&lt;b&gt;TF 값 계산&lt;/b&gt;&lt;br /&gt;각 문서에서 각 단어의 빈도를 계산한 후, 문서 내 총 단어 수로 나눠서 TF 값을 구합니다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;문서별 TF 계산&lt;/b&gt;&lt;br /&gt;-&amp;nbsp;문서 1:&amp;nbsp;&quot;나는&amp;nbsp;오늘&amp;nbsp;밥을&amp;nbsp;먹었다&quot;&amp;nbsp;(단어&amp;nbsp;수:&amp;nbsp;4개)&lt;br /&gt;-&amp;nbsp;문서 2:&amp;nbsp;&quot;밥을&amp;nbsp;먹고&amp;nbsp;운동을&amp;nbsp;했다&quot;&amp;nbsp;(단어&amp;nbsp;수:&amp;nbsp;4개)&lt;br /&gt;- 문서 3: &quot;오늘 운동을 마치고 밥을 먹었다&quot; (단어 수: 5개)&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 50.814%; height: 247px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;단어&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;문서 1 (TF)&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;문서 2 (TF)&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;문서 3 (TF)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;나는&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;1/4 = 0.25&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;0/4 = 0&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;0/5 = 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;오늘&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;1/4 = 0.25&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;0/4 = 0&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;1/5 = 0.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;밥을&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;1/4 = 0.25&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;1/4 = 0.25&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;1/5 = 0.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;먹었다&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;1/4 = 0.25&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;0/4 = 0&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;1/5 = 0.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;먹고&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;0/4 = 0&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;1/4 = 0.25&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;0/5 = 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;운동을&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;0/4 = 0&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;1/4 = 0.25&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;1/5 = 0.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;했다&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;0/4 = 0&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;1/4 = 0.25&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;0/5 = 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;마치고&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;0/4 = 0&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;0/4 = 0&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;1/5 = 0.2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;결과에서 보다시피 각 단어는 3개의 TF 값을 가집니다. (각 문서에서의 TF 값).&lt;br /&gt;예를 들어, &quot;밥을&quot;이라는 단어의 경우&lt;br /&gt;&amp;nbsp;&amp;nbsp;-&amp;nbsp;문서 1에서의&amp;nbsp;TF&amp;nbsp;값:&amp;nbsp;0.25&lt;br /&gt;&amp;nbsp;&amp;nbsp;-&amp;nbsp;문서 2에서의&amp;nbsp;TF&amp;nbsp;값:&amp;nbsp;0.2&lt;br /&gt;&amp;nbsp;&amp;nbsp;-&amp;nbsp;문서 3에서의&amp;nbsp;TF&amp;nbsp;값:&amp;nbsp;약&amp;nbsp;0.17&lt;br /&gt;&lt;br /&gt;따라서, 모든 단어가 각 문서별로 TF 값을 갖게 되어, 어휘 사전에 포함된 모든 단어에 대해 3개의 TF 값이 생성됩니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;2️⃣ Inverse Document Frequency (IDF)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;IDF는 특정 단어가 &lt;b&gt;전체 문서에서 얼마나 드물게 등장하는지&lt;/b&gt;를 측정합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;단어가 &lt;b&gt;많은 문서에서 등장할수록 IDF 값이 낮아지고&lt;/b&gt;, 반대로 &lt;b&gt;특정 문서에서만 등장하는 단어는 IDF 값이 높아집니다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이렇게 함으로써, 모든 문서에 자주 등장하는 &lt;b&gt;불필요한 단어들은 중요도가 낮아지고&lt;/b&gt;, 특정 문서에서만 등장하는 &lt;b&gt;특별한 단어들은 중요도가 높아집니다&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;\[&lt;br /&gt;\text {IDF}(t)&amp;nbsp;=&amp;nbsp;\log\left(\frac {\text {총&amp;nbsp;문서&amp;nbsp;수}}{1&amp;nbsp;+&amp;nbsp;\text {단어&amp;nbsp;}&amp;nbsp;t&amp;nbsp;\text {가&amp;nbsp;포함된&amp;nbsp;문서&amp;nbsp;수}}\right)&lt;br /&gt;\]&lt;br /&gt;&lt;br /&gt;- 총 문서 수: 데이터에 포함된 전체 문서의 개수입니다.&lt;br /&gt;- 단어 t가 포함된 문서 수: 단어 t가 등장한 문서의 개수입니다.&lt;br /&gt;-&amp;nbsp;로그를&amp;nbsp;사용하는&amp;nbsp;이유:&amp;nbsp;값이&amp;nbsp;너무&amp;nbsp;커지지&amp;nbsp;않도록&amp;nbsp;조절하기&amp;nbsp;위해서입니다.&lt;br /&gt;- 1을 더하는 이유: 단어가 포함된 문서 수가 0이 되는 경우를 방지하기 위해서입니다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;IDF 값 계산&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;다음과 같은 예제 문서들을 통해 IDF를 계산해 보겠습니다.&lt;br /&gt;&lt;br /&gt;문서 1:&amp;nbsp;&quot;나는&amp;nbsp;오늘&amp;nbsp;밥을&amp;nbsp;먹었다&quot;&lt;br /&gt;문서 2:&amp;nbsp;&quot;밥을&amp;nbsp;먹고&amp;nbsp;운동을&amp;nbsp;했다&quot;&lt;br /&gt;문서 3:&amp;nbsp;&quot;오늘&amp;nbsp;운동을&amp;nbsp;마치고&amp;nbsp;밥을&amp;nbsp;먹었다&quot;&lt;br /&gt;&lt;br /&gt;우선, 문서에서 고유한 단어들을 추출하여 어휘 사전을 만듭니다.&lt;br /&gt;Vocabulary: ['나는', '오늘', '밥을', '먹었다', '먹고', '운동을', '했다', '마치고']&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 62.4408%; height: 171px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 20%; height: 19px;&quot;&gt;단어&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 19px;&quot;&gt;포함된 문서 수&lt;/td&gt;
&lt;td style=&quot;width: 36.2011%; height: 19px;&quot;&gt;IDF 계산&lt;/td&gt;
&lt;td style=&quot;width: 20.0339%; height: 19px;&quot;&gt;IDF 값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 20%; height: 19px;&quot;&gt;나는&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 19px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 36.2011%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;log(3 / (1 + 1)) = log(3 / 2)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 20.0339%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;약 0.1761&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 20%; height: 19px;&quot;&gt;오늘&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 19px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 36.2011%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;log(3 / (1 + 2)) = log(3 / 3)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 20.0339%; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 20%; height: 19px;&quot;&gt;밥을&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 19px;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 36.2011%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;log(3 / (1 + 3)) = log(3 / 4)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 20.0339%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;약 -0.1249&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 20%; height: 19px;&quot;&gt;먹었다&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 19px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 36.2011%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;log(3 / (1 + 2)) = log(3 / 3)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 20.0339%; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 20%; height: 19px;&quot;&gt;먹고&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 19px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 36.2011%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;log(3 / (1 + 1)) = log(3 / 2)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 20.0339%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;약 0.1761&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 20%; height: 19px;&quot;&gt;운동을&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 19px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 36.2011%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;log(3 / (1 + 2)) = log(3 / 3)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 20.0339%; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 20%; height: 19px;&quot;&gt;했다&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 19px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 36.2011%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;log(3 / (1 + 1)) = log(3 / 2)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 20.0339%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;약 0.1761&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 20%; height: 19px;&quot;&gt;마치고&lt;/td&gt;
&lt;td style=&quot;width: 20%; height: 19px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 36.2011%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;log(3 / (1 + 1)) = log(3 / 2)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 20.0339%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;약 0.1761&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;위 결과를 보면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;단어 &quot;오늘&quot;은 문서 1과 문서 3에서 2번 등장합니다.&lt;br /&gt;&amp;nbsp;&amp;nbsp;-&amp;nbsp;\(\text {IDF}(\text {오늘})&amp;nbsp;=&amp;nbsp;\log\left(\frac {3}{1&amp;nbsp;+&amp;nbsp;2}\right)&amp;nbsp;=&amp;nbsp;\log(1)&amp;nbsp;=&amp;nbsp;0\)&lt;br /&gt;-&amp;nbsp;단어&amp;nbsp;&quot;나는&quot;은&amp;nbsp;문서 1에서만&amp;nbsp;등장합니다.&lt;br /&gt;&amp;nbsp;&amp;nbsp;-&amp;nbsp;\(\text {IDF}(\text {나는})&amp;nbsp;=&amp;nbsp;\log\left(\frac {3}{1&amp;nbsp;+&amp;nbsp;1}\right)&amp;nbsp;=&amp;nbsp;\log(1.5)&amp;nbsp;\approx&amp;nbsp;0.176\)&lt;br /&gt;-&amp;nbsp;단어&amp;nbsp;&quot;밥을&quot;은&amp;nbsp;모든&amp;nbsp;문서에서&amp;nbsp;등장합니다.&lt;br /&gt;&amp;nbsp;&amp;nbsp;-&amp;nbsp;\(\text {IDF}(\text {밥을})&amp;nbsp;=&amp;nbsp;\log\left(\frac {3}{1&amp;nbsp;+&amp;nbsp;3}\right)&amp;nbsp;=&amp;nbsp;\log(0.75)&amp;nbsp;\approx&amp;nbsp;-0.125\)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;- &quot;오늘&quot;: 여러 문서에 등장하므로 IDF 값이 낮습니다.(0에 가까움).&lt;br /&gt;- &quot;나는&quot;: 특정 문서에만 등장하므로 IDF 값이 높습니다.(약 0.176).&lt;br /&gt;- &quot;밥을&quot;: 모든 문서에 등장하므로 IDF 값이 매우 낮습니다.(심지어 음수).&lt;br /&gt;&lt;br /&gt;이렇게 IDF를 통해 &lt;b&gt;자주 등장하는 단어에는 낮은 가중치&lt;/b&gt;, &lt;b&gt;드물게 등장하는 단어에는 높은 가중치를 부여&lt;/b&gt;함으로써, 문서의 특징을 더 잘 반영할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;결과를 보셨다시피, IDF는 특정 단어가 &lt;b&gt;역수(Inverse)&lt;/b&gt;를 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다시 말해, 문서에서 자주 등장하는 단어일수록 중요도가 낮고, 반대로 드물게 등장하는 단어일수록 중요도가 높습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;왜 많이 등장하는 단어는 낮은 가중치를 받나요?&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;많이 등장하는 단어들(예: &quot;the&quot;, &quot;is&quot;, &quot;and&quot;)은 대부분의 문서에서 자주 나타나므로 문서의 내용을 구별하는 데 별로 도움이 되지 않습니다. 반면, 특정 문서에만 등장하는 고유한 단어는 해당 문서를 특징짓는 중요한 단어가 되기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;즉, &lt;b&gt;많이 등장&lt;/b&gt;하는 단어는 대부분의 문서에서 &lt;b&gt;흔히&lt;/b&gt; 나타나는 단어일 가능성이 높아서 중요도가 낮습니다. &amp;rarr; &lt;b&gt;낮은 IDF 값&lt;/b&gt;&lt;br /&gt;&lt;b&gt;적게 등장&lt;/b&gt;하는 단어는 특정 문서에만 등장할 가능성이 높아서 그 문서를 설명하는 &lt;b&gt;중요한&lt;/b&gt; 단어일 수 있습니다. &amp;rarr; &lt;b&gt;높은 IDF 값&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;TF-IDF란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;TF-IDF(Term Frequency-Inverse Document Frequency)는 &lt;b&gt;단어의 빈도(TF)&lt;/b&gt;와 &lt;b&gt;역면서 빈도(IDF)&lt;/b&gt;를 &lt;b&gt;곱하여&lt;/b&gt; &lt;b&gt;각 단어의 가중치&lt;/b&gt;를 계산하는 방식입니다. 이를 통해, 단어가 문서에서 자주 등장하지만 모든 문서에 공통적으로 나타나는 단어는 낮은 가중치를 받고, 특정 문서에서만 자주 등장하는 단어는 높은 가중치를 받습니다.&lt;br /&gt;&lt;br /&gt;TF와 IDF를 결합한 TF-IDF 공식은 다음과 같습니다.&lt;br /&gt;&lt;br /&gt;\[&lt;br /&gt;\text {TF-IDF}(t,&amp;nbsp;d)&amp;nbsp;=&amp;nbsp;\text {TF}(t,&amp;nbsp;d)&amp;nbsp;\times&amp;nbsp;\text {IDF}(t)&lt;br /&gt;\]&lt;br /&gt;&lt;br /&gt;-&amp;nbsp;\(&amp;nbsp;t&amp;nbsp;\):&amp;nbsp;특정&amp;nbsp;단어(term)&lt;br /&gt;-&amp;nbsp;\(&amp;nbsp;d&amp;nbsp;\):&amp;nbsp;특정&amp;nbsp;문서(document)&lt;br /&gt;- TF: 특정 단어가 문서 내에서 얼마나 자주 등장하는지 나타냄&lt;br /&gt;- IDF: 특정 단어가 전체 문서에서 얼마나 드물게 등장하는지 나타냄&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;&lt;b&gt;TF-IDF 계산&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;앞서 사용한 예제 문서들을 다시 사용해 TF-IDF를 직접 계산해 보겠습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 81.5117%; height: 189px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 37px;&quot;&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 37px;&quot;&gt;단어&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 37px;&quot;&gt;문서 1(TF)&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 37px;&quot;&gt;문서 2(TF)&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 37px;&quot;&gt;문서 3(TF)&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 37px;&quot;&gt;IDF&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 37px;&quot;&gt;문서 1 &lt;br /&gt;(TF-IDF)&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 37px;&quot;&gt;문서 2&lt;br /&gt;(TF-IDF)&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 37px;&quot;&gt;문서 2&lt;br /&gt;(TF-IDF)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;나는&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0.25&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;0.1761&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0.044&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;오늘&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0.25&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0.2&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;밥을&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0.25&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0.25&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0.2&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;-0.1249&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;-0.0312&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;-0.0312&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;-0.025&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;먹었다&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0.25&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0.2&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;먹고&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0.25&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;0.1761&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;0.0440&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;운동을&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0.25&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0.2&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;했다&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0.25&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;0.1761&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;0.0440&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;마치고&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0.2&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;0.1761&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 11.1111%; text-align: center; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;0.0352&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;- &quot;나는&quot;이라는 단어는 문서 1에서만 등장했기 때문에, 문서1에서 높은 TF-IDF 값을 가집니다.&lt;br /&gt;- &quot;밥을&quot;은 모든 문서에서 등장하기 때문에, TF는 높지만 IDF가 낮아 TF-IDF 값이 작아집니다.&lt;br /&gt;- &quot;마치고&quot;는 문서 3에서만 등장하기 때문에 문서3에서 높은 TF-IDF 값을 가집니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;&lt;b&gt;Python을 사용한 TF-IDF 계산&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Python의 `&lt;b&gt;TfidfVectorizer&lt;/b&gt;`를&amp;nbsp;사용해&amp;nbsp;직접&amp;nbsp;TF-IDF를&amp;nbsp;계산할&amp;nbsp;수도&amp;nbsp;있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1731485456232&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.feature_extraction.text import TfidfVectorizer
import pandas as pd

# 예제 문서 리스트
corpus = [
    &quot;나는 오늘 밥을 먹었다&quot;,
    &quot;밥을 먹고 운동을 했다&quot;,
    &quot;오늘 운동을 마치고 밥을 먹었다&quot;
]

# TfidfVectorizer를 사용해 TF-IDF 행렬 생성
vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform(corpus)

# TF-IDF 행렬을 Pandas DataFrame으로 변환
tfidf_df = pd.DataFrame(tfidf_matrix.toarray(), columns=vectorizer.get_feature_names_out())
print(tfidf_df)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1268&quot; data-origin-height=&quot;298&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AyiTq/btsKHXYkQEk/7s67QW7hXgeLkJih6734j1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AyiTq/btsKHXYkQEk/7s67QW7hXgeLkJih6734j1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AyiTq/btsKHXYkQEk/7s67QW7hXgeLkJih6734j1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAyiTq%2FbtsKHXYkQEk%2F7s67QW7hXgeLkJih6734j1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;638&quot; height=&quot;150&quot; data-origin-width=&quot;1268&quot; data-origin-height=&quot;298&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;TF-IDF의 활용&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 문서 분류: 중요한 단어를 찾아 문서의 주제를 분류하는 데 활용합니다.&lt;br /&gt;- 문서 유사도 분석: TF-IDF 벡터를 이용해 코사인 유사도(Cosine&amp;nbsp;Similarity)를 계산하여 문서 간 유사도를 평가합니다.&lt;br /&gt;- 검색 엔진 최적화: 사용자의 검색어와 문서 간 관련성을 평가하여 검색 결과의 순위를 매기는 데 활용됩니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;&lt;b&gt;TF-IDF의 장단점&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;장점&lt;br /&gt;-&amp;nbsp;단어의&amp;nbsp;빈도뿐만&amp;nbsp;아니라&amp;nbsp;중요도를&amp;nbsp;고려하므로&amp;nbsp;BoW보다&amp;nbsp;효율적입니다.&lt;br /&gt;-&amp;nbsp;중요한&amp;nbsp;단어에&amp;nbsp;높은&amp;nbsp;가중치를&amp;nbsp;부여해&amp;nbsp;문서의&amp;nbsp;특성을&amp;nbsp;잘&amp;nbsp;파악할&amp;nbsp;수&amp;nbsp;있습니다.&lt;br /&gt;&lt;br /&gt;단점&lt;br /&gt;-&amp;nbsp;문서가&amp;nbsp;많아질수록&amp;nbsp;희소&amp;nbsp;행렬(Sparse&amp;nbsp;Matrix)&amp;nbsp;문제가&amp;nbsp;여전히&amp;nbsp;존재합니다.&lt;br /&gt;-&amp;nbsp;문서&amp;nbsp;내&amp;nbsp;단어의&amp;nbsp;순서&amp;nbsp;정보가&amp;nbsp;손실됩니다.&lt;br /&gt;-&amp;nbsp;단어의&amp;nbsp;문맥을&amp;nbsp;이해하지&amp;nbsp;못해&amp;nbsp;의미가&amp;nbsp;유사한&amp;nbsp;단어를&amp;nbsp;구분하지&amp;nbsp;못합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;하지만,&lt;br /&gt;TF-IDF는&amp;nbsp;단어의&amp;nbsp;빈도와&amp;nbsp;가중치를&amp;nbsp;기반으로&amp;nbsp;하여&amp;nbsp;문맥을&amp;nbsp;반영하지&amp;nbsp;않습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이를&amp;nbsp;보완하기&amp;nbsp;위해&amp;nbsp;Word2Vec,&amp;nbsp;GloVe,&amp;nbsp;BERT와&amp;nbsp;같은&amp;nbsp;임베딩(embedding)&amp;nbsp;기법들이&amp;nbsp;사용됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이러한&amp;nbsp;기법들은&amp;nbsp;단어&amp;nbsp;간의&amp;nbsp;문맥적&amp;nbsp;관계를&amp;nbsp;반영하여&amp;nbsp;더&amp;nbsp;나은&amp;nbsp;성능을&amp;nbsp;제공합니다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>pytorch</category>
      <category>CountVectorizer</category>
      <category>DTM</category>
      <category>nlp</category>
      <category>TF-IDF</category>
      <category>TfidfVectorizer</category>
      <category>검색엔진</category>
      <category>데이터분석</category>
      <category>머신러닝</category>
      <category>자연어처리</category>
      <category>텍스트전처리</category>
      <category>티스토리챌린지</category>
      <author>ISFP의 블로그</author>
      <guid isPermaLink="true">https://resultofeffort.tistory.com/145</guid>
      <comments>https://resultofeffort.tistory.com/145#entry145comment</comments>
      <pubDate>Fri, 22 Nov 2024 12:23:43 +0900</pubDate>
    </item>
    <item>
      <title>[pytorch] Bag of Words (BOW) | CountVectorizer</title>
      <link>https://resultofeffort.tistory.com/144</link>
      <description>&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Bag of Words란?&lt;/b&gt;&lt;/h2&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Bag of Words의 개념과 활용&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Bag of Words (BoW)는 문서를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;&lt;b&gt;단어의 빈도수&lt;/b&gt;&lt;/u&gt;로 표현하는 방법으로,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;&lt;b&gt;단어의 순서를 무시&lt;/b&gt;&lt;/u&gt;하고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;&lt;b&gt;각 단어가 문서에 얼마나 자주 등장했는지&lt;/b&gt;&lt;/u&gt;를 수치화하는 기법입니다. BoW는 단순하지만, 자연어 처리에서 기본적인 텍스트 표현 방법으로 널리 사용되며, 특히 문서 분류, 유사도 측정, 추천 시스템 등에서 유용합니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Bag of Words의 특징&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;BoW는 텍스트를 단어의 출현 빈도 기반으로 표현하기 때문에 두 가지 주요 특징을 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;1.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;단어 순서 무시&lt;/b&gt;: BoW에서는 문장의 구조나 단어 순서를 전혀 고려하지 않습니다. 단어의 순서가 바뀌어도 단어 빈도만 같다면 BoW 벡터는 동일합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;2.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;단어 빈도 중심&lt;/b&gt;: BoW 벡터는 단어가 등장한 횟수만을 기록합니다. 특정 단어가 자주 등장할수록 해당 단어의 중요성이 높다고 가정하는 방식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이러한 특징 덕분에 BoW는 계산이 단순하고 직관적이지만, 문맥이나 의미를 반영하지 못하는 한계도 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Bag of Words 예시&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;아래 예시 문장의 등장 횟수를 수치화해서 단어의 빈도를 출력해 보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1731487079242&quot; class=&quot;coffeescript&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;from konlpy.tag import Okt  # konlpy의 Okt 형태소 분석기 불러오기

okt = Okt()  # Okt 형태소 분석기 객체 생성

def build_bag_of_words(document):
    document = document.replace('.', '')      # 문장부호 '.' 제거
    tokenized_document = okt.morphs(document) # 형태소(단어) 단위로 토큰화

    word_to_index = {}  # 단어와 인덱스를 매핑할 딕셔너리
    bow = []            # Bag of Words(BOW)를 저장할 리스트

    for word in tokenized_document:
        if word not in word_to_index:                # 단어가 처음 등장하면
            word_to_index[word] = len(word_to_index) # 고유 인덱스 할당
            bow.insert(len(word_to_index) - 1, 1)    # BOW 리스트에 해당 단어 위치에 1 추가
        else:
            index = word_to_index.get(word)  # 기존에 있던 단어라면 해당 인덱스를 가져와서
            bow[index] += 1                  # 등장 횟수를 1 증가시킴

    return tokenized_document, word_to_index, bow  # 단어-인덱스 매핑과 BOW 벡터 반환&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1731487079243&quot; class=&quot;stylus&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;doc1 = &quot;The dog loves playing in the park and the dog enjoys chasing birds.&quot;
tokenized_document, vocab, bow = build_bag_of_words(doc1)
print('토큰화 : ',tokenized_document)
print('정수 인코딩 :', vocab)
print('각 단어의 등장 횟수 :', bow)

&amp;gt; 토큰화 :  ['The', 'dog', 'loves', 'playing', 'in', 'the', 'park', 'and', 'the', 'dog', 'enjoys', 'chasing', 'birds']
정수 인코딩 : {'The': 0, 'dog': 1, 'loves': 2, 'playing': 3, 'in': 4, 'the': 5, 'park': 6, 'and': 7, 'enjoys': 8, 'chasing': 9, 'birds': 10}
각 단어의 등장 횟수 : [1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1]&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 id=&quot;3-countvectorizer-bow&quot; style=&quot;background-color: #ffffff; color: #24292f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;CountVectorizer 클래스로 BoW 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;CountVectorizer&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;클래스를 사용하여 주어진 문장에서 Bag of Words (BoW)를 생성하는 방법을 보여줍니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1731487079245&quot; class=&quot;yaml&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;from sklearn.feature_extraction.text import CountVectorizer

corpus = [&quot;The dog loves playing in the park and the dog enjoys chasing birds.&quot;]
vector = CountVectorizer()

print('각 단어의 등장 횟수 :', vector.fit_transform(corpus).toarray()) 
print('정수 인코딩 :',vector.vocabulary_)

&amp;gt; 각 단어의 등장 횟수 : [[1 1 1 2 1 1 1 1 1 3]]
정수 인코딩 : {'the': 9, 'dog': 3, 'loves': 6, 'playing': 8, 'in': 5, 'park': 7, 'and': 0, 'enjoys': 4, 'chasing': 2, 'birds': 1}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;출력된 결과를 보면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Bow의 결과가 좀 다릅니다.&lt;/p&gt;
&lt;p id=&quot;3-countvectorizer-bow&quot; style=&quot;background-color: #ffffff; color: #24292f; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;CountVectorizer 클래스를 사용하지 않은 Bow는&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot;&gt;각 단어의 등장 횟수 : [1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1]의 결과가 나왔으며,&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;3-countvectorizer-bow&quot; style=&quot;background-color: #ffffff; color: #24292f; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;CountVectorizer 클래스를 사용한 Bow는&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot;&gt;각 단어의 등장 횟수 : [[1 1 1 2 1 1 1 1 1 3]]의 결과가 나왔습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;두 방식에서 생성된 Bag of Words (BoW)의 결과가 서로 다른 이유는,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;단어의 전처리 방식과 단어 집합 구성 방식&lt;/b&gt;이 다르기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;1️⃣&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;단어 집합 구성 방식&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;CountVectorizer를 사용하지 않은 BoW&lt;/b&gt;에서는 모든 단어와 구두점 등을 포함해 단어 집합을 구성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;CountVectorizer를 사용한 BoW&lt;/b&gt;에서는 기본적으로 불필요한 구두점 등을 제거하고, 각 단어를 소문자로 변환하는 등의 추가 전처리를 수행합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;2️⃣&lt;/span&gt;구두점 및 대소문자 처리&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;CountVectorizer는 기본적으로 구두점과 대소문자를 무시하고, 모든 텍스트를 소문자로 변환하여 단어 집합을 구성합니다. 예를 들어, 문장에 &quot;The&quot;와 &quot;the&quot;가 함께 등장하더라도 CountVectorizer는 이를 같은 단어로 간주하고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;the&quot;로 통일&lt;/b&gt;합니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;반면, CountVectorizer를 사용하지 않은 BoW에서는 대소문자를 구분하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;The&quot;와 &quot;the&quot;를 각각 다른 단어로 인식&lt;/b&gt;하고 별도의 인덱스를 부여합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(위 코드에서도 CountVectorizer를 사용하지 않은 BoW에서는 대문자 The는 0 인덱스로, 소문자 the는 5 인덱스로 처리가 되었습니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;3️⃣&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;출력 포맷&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;CountVectorizer&lt;/b&gt;의 결과는 일반적으로 2차원 배열 형태(&lt;span&gt;[[...]]&lt;/span&gt;)로 반환됩니다. 여러 문서의 BoW를 동시에 표현할 수 있기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;반면, 직접 구현한 BoW의 결과는 단일 벡터(&lt;span&gt;[...]&lt;/span&gt;)로 나타났습니다. 이는 단일 문서에 대해서만 BoW를 생성했기 때문입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 id=&quot;3-countvectorizer-bow&quot; style=&quot;background-color: #ffffff; color: #24292f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;CountVectorizer + 불용어 제거 (사용자가 직접 정의)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;문장의 의미 전달에 큰 영향을 미치지 않으면서 자주 등장하는 단어들인 불용어를 정의하여 제거합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1731487079247&quot; class=&quot;yaml&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;from sklearn.feature_extraction.text import CountVectorizer
from nltk.corpus import stopwords

text = [&quot;The dog loves playing in the park and the dog enjoys chasing birds.&quot;]
vect = CountVectorizer(stop_words=[&quot;the&quot;, &quot;and&quot;, &quot;in&quot;])

print('bag of words vector :',vect.fit_transform(text).toarray())
print('vocabulary :',vect.vocabulary_)

&amp;gt; bag of words vector : [[1 1 1 2 1 1 1 1]]
vocabulary : {'dog': 3, 'loves': 5, 'playing': 7, 'park': 6, 'and': 0, 'enjoys': 4, 'chasing': 2, 'birds': 1}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;3-countvectorizer-bow&quot; style=&quot;background-color: #ffffff; color: #24292f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;CountVectorizer에서 제공하는 자체 불용어 사용&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1731487079248&quot; class=&quot;yaml&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;from sklearn.feature_extraction.text import CountVectorizer

text = [&quot;The dog loves playing in the park and the dog enjoys chasing birds.&quot;]
vect = CountVectorizer(stop_words=&quot;english&quot;)  # 문자열로 &quot;english&quot; 설정

print('bag of words vector :', vect.fit_transform(text).toarray()) 
print('vocabulary :', vect.vocabulary_)

&amp;gt; bag of words vector : [[1 1 2 1 1 1 1]]
vocabulary : {'dog': 2, 'loves': 4, 'playing': 6, 'park': 5, 'enjoys': 3, 'chasing': 1, 'birds': 0}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;3-countvectorizer-bow&quot; style=&quot;background-color: #ffffff; color: #24292f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;NLTK에서 지원하는 불용어 사용&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1731487079249&quot; class=&quot;yaml&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;from nltk.corpus import stopwords

text = [&quot;The dog loves playing in the park and the dog enjoys chasing birds.&quot;]
stop_words = stopwords.words(&quot;english&quot;)
vect = CountVectorizer(stop_words=stop_words)

print('bag of words vector :',vect.fit_transform(text).toarray()) 
print('vocabulary :',vect.vocabulary_)

&amp;gt; bag of words vector : [[1 1 2 1 1 1 1]]
vocabulary : {'dog': 2, 'loves': 4, 'playing': 6, 'park': 5, 'enjoys': 3, 'chasing': 1, 'birds': 0}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Bag of Words의 한계&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;BoW는 단순한 방법으로 텍스트를 표현하지만, 아래와 같은 한계도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;문맥 정보 부족&lt;/b&gt;: BoW는 단어의 순서나 문맥을 반영하지 않기 때문에, 단어가 주변 단어와 함께 가지는 의미를 표현할 수 없습니다. 예를 들어, &amp;ldquo;강아지가 고양이를 쫓는다&amp;rdquo;와 &amp;ldquo;고양이가 강아지를 쫓는다&amp;rdquo;는 서로 다른 의미이지만, BoW에서는 같은 단어들이 등장하는 것으로만 인식합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;단어의 중요도 반영 어려움&lt;/b&gt;: 모든 단어의 빈도만 반영하기 때문에, 자주 등장하지만 정보량이 적은 불용어(stop words)들도 BoW 벡터에 포함됩니다. 이를 해결하기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;TF-IDF&lt;/b&gt;와 같은 가중치 기법을 추가로 활용하기도 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>pytorch</category>
      <category>BagofWords</category>
      <category>bow</category>
      <category>CountVectorizer</category>
      <category>nlp</category>
      <category>데이터분석</category>
      <category>불용어처리</category>
      <category>오블완</category>
      <category>자연어처리</category>
      <category>텍스트마이닝</category>
      <category>텍스트분석</category>
      <category>티스토리챌린지</category>
      <category>형태소분석</category>
      <author>ISFP의 블로그</author>
      <guid isPermaLink="true">https://resultofeffort.tistory.com/144</guid>
      <comments>https://resultofeffort.tistory.com/144#entry144comment</comments>
      <pubDate>Tue, 19 Nov 2024 00:15:37 +0900</pubDate>
    </item>
  </channel>
</rss>