<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Kwon's 데이터분석기</title>
    <link>https://koy0911.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Fri, 26 Jun 2026 01:36:38 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>DataKwon</managingEditor>
    <item>
      <title>기초적인 SQL 코드 및 정리 2</title>
      <link>https://koy0911.tistory.com/11</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;저번 글인 SQL코드 및 정리의 마지막 설명이었던 '함수 활용하기'에 이어서 작성하도록 하겠다.&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 데이터의 그룹화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 그룹화 하는 GROUP BY를 사용하면 집단 간 차이를 좀 더 자세히 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그룹화 하는 방법은 열 이름으로 그룹화 하는 방법과 열 위치로 그룹화 하는 방법 2개가 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 GROUP BY 구문 그룹화에 대한 코드 예시이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705219168004&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 열 이름으로 그룹화
SELECT cust_id, seg, AVG(annl_rev) AS annl_rev
FROM PPC_201312
GROUP BY seg;

# 열 위치로 그룹화
SELECT cust_id, seg, AVG(annl_rev) AS annl_rev
FROM PPC_201312
GROUP BY 2;

# 심화
SELECT card_flg, loan_flg, fund_fnc, COUNT(*) AS cnt
FROM PPC_201312
GROUP BY 1, 2;  # 또는 GROUP BY card_flg, loan_flg; 사용&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 유용한 지식&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 원하는 열을 group by 절에 포함 할 수 있다. GROUP BY절은 하나의 기준으로만 그룹화가 가능한 것이 아닌, 여러 열을 지정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- GROUP BY절은 WHERE 조건절 뒤에 위치하고 ORDER BY절 앞에 위치한다. ORDER BY절은 항상 마지막 문장에 위치하기 때문에 GROUP BY절이 ORDER BY절 뒤에 가면 오류가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 그룹화될 열에 NULL값 포함할 경우 NULL값도 그룹화가 된다.&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;2. 그룹화 된 데이터 필터링&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그룹화 된 데이터 필터링을 하기 위해선 HAVING 절을 사용하여 조건을 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 그룹화 데이터 필터링 코드 구조이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705219564453&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT 그룹화할 열 이름, 집계함수
FROM 테이블명
WHERE 조건절
GROUP BY 열 이름 or 열 위치
HAVING 집계 함수 조건;&lt;/code&gt;&lt;/pre&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;pre id=&quot;code_1705219710341&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# GROUP BY ~~ HAVING 조건절; 예시 코드
SELECT cust_nm, SUM(sales_amt) AS sales_tot
FROM PROD_SALES
WHERE sales_amt &amp;gt;= 50000
GROUP BY cust_nm  #또는 1
HAVING SUM(sales_amt) &amp;gt;= 100000;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드를 보면 cust_nm과 sales_amt를 모두 더한 값을 sales_tot로 두개의 열을 들고오는데, sales_amt가 50000이상인 값만 들고오고, GROUP BY cust_nm을 통해 cust_nm을 기준으로 그룹화를 시켜준다. 이렇게 나온 데이터 행 중 sales_amt가 100000 이상인 값만 불러오는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 유용한 지식&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- WHERE 조건절의 조건은 데이터 그룹화 되기 전 필터링 하고, HAVING절의 조건은 데이터가 그룹화된 후 필터링을 수행한다.&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;● 테이블 합치기 - 열(Column) 합치기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 내부 조인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부 조인은 두 테이블에 공통으로 존재하는 키값이 되는 모든 행을 나타낸다. 간단하게 얘기하면 교집합이라고 생각하면 된다. 내부 조인에는 크게 2가지 방법이 있다. 아래는 내부 조인의 문법이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705289984846&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# FROM/WHERE을 사용해 내부 조인하는 방법 &amp;amp; 별칭 X
SELECT 테이블명1.열이름1, 테이블명2.열이름2
FROM 테이블명1, 테이블명2
WHERE 테이블명1.KEY = 테이블명2.KEY;
## FROM/WHERE을 사용해 내부 조인하는 방법 &amp;amp; 별칭 O: AS 생략 가능하다.
SELECT 별칭1.열이름1, 별칭2.열이름2
FROM 테이블명1 (AS) 별칭1, 테이블명2 (AS) 별칭2
WHERE 별칭1.KEY = 별칭2.KEY;

# INNER JOIN 사용 &amp;amp; 별칭 X
SELECT 테이블명1.열이름1, 테이블명2.열이름2
FROM 테이블명1 INNER JOIN 테이블명2
ON 테이블명1.KEY = 테이블명2.KEY;
# INNER JOIN 사용 &amp;amp; 별칭 O: AS 생략 가능
SELECT 별칭1.열이름1, 별칭2.열이름2
FROM 테이블명1 (AS) 별칭1 INNER JOIN 테이블명2 (AS) 별칭2
ON 별칭1.KEY = 별칭2.KEY;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드를 보면 FROM/WHERE을 사용해 내부 조인을 하는 방법도 있지만, 새로 알아볼 방법으로 INNER JOIN에 대해서&amp;nbsp; 알아볼 것이다. 그리고 조인을 할 때 별칭을 지정하는 AS는 생략이 가능하며, 조인을 사용할 때에는 ON 구문을 통해서 키 값을 매칭시켜 연결시켜준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래에 내부 조인인 INNER JOIN에 대한 예시 코드로 알아보도록 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1705290361588&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# INNER JOIN: CUSTOMER, ORDERS, EMPLOYEE 테이블 이용해 주문이력 있는 cust_id, cust_nm, order_id,
# emp_id, nm을 나타내본다.
SELECT TMP1.cust_id, TMP1.cust_nm, TMP2.order_id, TMP2.emp_id, TMP3.nm
FROM CUSTOMER TMP1
	INNER JOIN ORDERS TMP2 ON TMP1.cust_id = TMP2.cust_id
    INNER JOIN EMPLOYEE TMP3 ON TMP2.emp_id = TMP3.emp_id;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드를 보면 CUSTOMER 테이블을 TMP1, ORDERS 테이블을 TMP2, EMPLOYEE 테이블을 TMP3로 지정하면서 TMP1.cust_id와 TMP2.cust_id를 내부 조인을 해주고, 이어서 TMP2.emp_id와 TMP3.emp_id를 내부조인 시켜주는 것을 확인할 수 있었다. 이렇게 여러개의 테이블에 대한 열을 합쳐서 데이터를 들고올 수 있다.&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;2. 외부 조인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부 조인은 내부 조인처럼 여러 테이블 간 일치하는 행을 결합하는 것은 같다. 하지만 조인 조건에 맞지 않는 행을 제외하는 내부 조인과 다르게 외부 조인은 조인 조건에 맞지 않는 행도 결과에 NULL값으로 출력되서 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부 조인은 3가지의 종류가 존재한다. 아래는 외부 조인의 3가지 방법에 대한 코드 구문이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705291295945&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# LEFT OUTER JOIN: OUTER는 생략이 가능
SELECT 별칭1.열이름1, 별칭2.열이름2
FROM 테이블명 (AS) 별칭1 LEFT (OUTER) JOIN 테이블명2 (AS) 별칭2
ON 별칭1.KEY = 별칭2.KEY;

# RIGHT OUTER JOIN: OUTER는 생략 가능
SELECT 별칭1.열이름1, 별칭2.열이름2
FROM 테이블명 (AS) 별칭1 RIGHT (OUTER) JOIN 테이블명2 (AS) 별칭2
ON 별칭1.KEY = 별칭2.KEY;

# FULL OUTER JOIN: OUTER는 생략 가능
SELECT 별칭1.열이름1, 별칭2.열이름2
FROM 테이블명 (AS) 별칭1 FULL (OUTER) JOIN 테이블명2 (AS) 별칭2
ON 별칭1.KEY = 별칭2.KEY;&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;719&quot; data-origin-height=&quot;389&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDzhv7/btsDwB8Adkv/p92XG0KJE93StgMf59knEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDzhv7/btsDwB8Adkv/p92XG0KJE93StgMf59knEk/img.png&quot; data-alt=&quot;간단한 예시 테이블 데이터&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDzhv7/btsDwB8Adkv/p92XG0KJE93StgMf59knEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDzhv7%2FbtsDwB8Adkv%2Fp92XG0KJE93StgMf59knEk%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;554&quot; height=&quot;300&quot; data-origin-width=&quot;719&quot; data-origin-height=&quot;389&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;간단한 예시 테이블 데이터&lt;/figcaption&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;2-1. LEFT OUTER JOIN은 왼쪽 테이블을 기준으로 조인하는 방법이다. 만약 왼쪽 테이블에 존재하지만 오른쪽 테이블에 존재하지 않는 키값이 존재한다면 NULL값이 반환된다. 아래는 간단한 LEFT OUTER JOIN의 예시코드와 결과이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705291562962&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# LEFT OUTER JOIN 예시 코드
SELECT employees.employee_id, employees.employee_name, departments.department_name
FROM employees
LEFT OUTER JOIN departments ON employees.department_id = departments.department_id;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드의 LEFT OUTER JOIN 결과를 보면 아래와 같은 결과가 출력된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;395&quot; data-origin-height=&quot;132&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/my9q4/btsDwDZB8WC/QIrcfShb96yScxyuLUEMvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/my9q4/btsDwDZB8WC/QIrcfShb96yScxyuLUEMvk/img.png&quot; data-alt=&quot;LEFT OUTER JOIN 예시 코드 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/my9q4/btsDwDZB8WC/QIrcfShb96yScxyuLUEMvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmy9q4%2FbtsDwDZB8WC%2FQIrcfShb96yScxyuLUEMvk%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;356&quot; height=&quot;119&quot; data-origin-width=&quot;395&quot; data-origin-height=&quot;132&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;LEFT OUTER JOIN 예시 코드 결과&lt;/figcaption&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;2-2. RIGHT OUTER JOIN은 오른쪽 테이블을 기준으로 조인하는 방법으로 LEFT OUTER JOIN과 반대로 오른쪽 테이블에는 존재하지만 왼쪽 테이블에는 존재하지 않는 키값이 있다면 NULL값이 반환된다. 아래는 간단한 LEFT OUTER JOIN 예시코드와 결과이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705291872315&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# RIGHT OUTER JOIN 예시 코드
SELECT employees.employee_id, employees.employee_name, departments.department_name
FROM employees
RIGHT OUTER JOIN departments ON employees.department_id = departments.department_id;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 RIGHT OUTER JOIN 예시 코드의 결과를 보면 아래와 같은 결과가 출력이 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;134&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oze8L/btsDp6JbyjZ/3DLriGAigmIs0WLwWufJEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oze8L/btsDp6JbyjZ/3DLriGAigmIs0WLwWufJEk/img.png&quot; data-alt=&quot;RIGHT OUTER JOIN 예시 코드 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oze8L/btsDp6JbyjZ/3DLriGAigmIs0WLwWufJEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Foze8L%2FbtsDp6JbyjZ%2F3DLriGAigmIs0WLwWufJEk%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;420&quot; height=&quot;134&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;134&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;RIGHT OUTER JOIN 예시 코드 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 LEFT OUTER JOIN과 RIGHT OUTER JOIN의 결과가 다르게 나온 것을 알 수 있다. 이는 조인되는 기준이 왼쪽 테이블인지, 오른쪽 테이블인지에 따라 사용되는 구문이기 때문이다.&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;2-3. FULL OUTER JOIN은 왼쪽(LEFT), 오른쪽(RIGHT)로 나누는 것이 아닌 왼쪽, 오른쪽의 모든 행이 반환되는 것이다. 즉, LEFT OUTER JOIN과 RIGHT OUTER JOIN을 합쳐놓은 형태이다. 아래는 간단한 FULL OUTER JOIN 예시코드와 결과이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705293176458&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# FULL OUTER JOIN 예시 코드
SELECT employees.employee_id, employees.employee_name, departments.department_name
FROM employees
FULL OUTER JOIN departments ON employees.department_id = departments.department_id;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 FULL OUTER JOIN 예시 코드 결과를 보면, 왜 LEFT와 RIGHT OUTER JOIN을 합친 것인지 이해할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;404&quot; data-origin-height=&quot;154&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZOgba/btsDsYXvDVG/yEv2qqlwRbLK5G2Nhk1ov1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZOgba/btsDsYXvDVG/yEv2qqlwRbLK5G2Nhk1ov1/img.png&quot; data-alt=&quot;FULL OUTER JOIN 예시 코드 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZOgba/btsDsYXvDVG/yEv2qqlwRbLK5G2Nhk1ov1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZOgba%2FbtsDsYXvDVG%2FyEv2qqlwRbLK5G2Nhk1ov1%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;404&quot; height=&quot;154&quot; data-origin-width=&quot;404&quot; data-origin-height=&quot;154&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;FULL OUTER JOIN 예시 코드 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단 FULL OUTER JOIN의 문제점으로는 ACCESS, MYSQL 등 몇몇 DBMS에서는 FULL OUTER JOIN 키워드가 지원이 되지 않기 때문에 자신이 사용하는 DBMS가 무엇인지 확인해보고 사용을 해야한다.&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;● 테이블 합치기 - 행(Row) 합치기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. UNION 연산자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두개 이상의 테이블의 행을 합칠 때 UNION연산자를 사용한다. 두 개 이상의 SELECT문의 결과값을 합치는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UNION 연산자 사용시 주의점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- UNION 연산자로 합쳐지는 SELECT문의 열의 숫자는 반드시 동일해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SELECT문의 각 데이터 타입은 일치해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 두가지 주의점을 명심하면서 UNION 연산자를 사용해야 한다. 또한 UNION연산자는 중복되는 값이 존재하면 한가지만 표시하는 특징이 있다. 만약 중복되는 값 또한 모두 보여주고 싶다면, 나중에 설명할 UNION ALL을 사용하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 UNION연산자 코드 구문과 예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705300898793&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# UNION연산자 구문
SELECT 열이름1, 열이름2 FROM 테이블명1 WHERE 조건절
UNION
SELECT 열이름1, 열이름2 FROM 테이블명2 WHERE 조건절
ORDER BY 1;

# UNION연산자 예시 코드
SELECT cust_nm FROM CUSTOMERS
UNION
SELECT nm FROM EMPLOYEE
ORDER BY 1;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시코드를 살펴보면 CUSTOMERS 테이블의 cust_nm과 EMPLOYEE테이블의 nm을 UNION연산자를 통해 합치는 작업을 수행한다. 이때 cust_nm과 nm은 테이블에 저장된 이름만 다를 뿐이지 데이터 유형은 같기 때문에 결합 할 수 있다. 즉,&amp;nbsp; &lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;열 이름이 다르더라도 UNION을 사용할 수 있는 경우는 제한적이고, 데이터 유형과 순서가 일치할 때 주로 사용한다고 보면 된다.&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;2. UNION ALL 연산자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UNION ALL연산자 또한 UNION과 마찬가지로 두개 이상의 테이블의 행을 합칠 때 사용한다. UNION과 UNION ALL 연산자의 차이는 UNION 연산자는 중복을 허용하지 않지만, UNION ALL 연산자는 중복까지 허용해서 출력을 해준다는 차이점이 존재한다. 아래는 UNION ALL 연산자 코드 구문과 예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705301619518&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# UNION ALL 코드 구문
SELECT 열이름1, 열이름2 FROM 테이블명1 WHERE 조건절
UNION ALL  # UNION ALL은 중복 값까지 다 나옴
SELECT 열이름1, 열이름2 FROM 테이블명2 WHERE 조건절
ORDER BY 1;  # 또는 ORDER BY 열이름1

# UNION ALL 예시 코드
SELECT cust_id FROM CUSTOMERS
UNION ALL
SELECT cust_id FROM ORDERS
ORDER BY 1; # 또는 ORDER BY cust_id&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;위 UNION ALL 연산자 코드는 UNION 연산자와 큰 차이가 존재하지 않지만, 중복값이 출력된다는 차이가 존재한다.&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;● 하위 쿼리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 쿼리란 하나의 SQL 문장에 속하는 또 다른 SQL문장으로, 두 번 이상의 질의를 통해 얻을 수 있는 결과를 한 번의 질의로 해결할 수 있다. 하위 쿼리를 잘 사용하면 복잡한 SQL 문장도 간단하게 만들 수 있고 DBMS 데이터 처리 속도를 빠르게 향상 시킬 수 있다.&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;1. FROM절의 하위 쿼리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 조건에 맞는 대상자 선정 후 요약할 때&lt;/p&gt;
&lt;pre id=&quot;code_1705304278343&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 조건에 맞는 대상자 선정 후 요약할 경우 SQL문법 구조
SELECT 열이름1, 열이름2
FROM (SELECT *
	FROM 테이블명
    WHERE 조건절) (AS) 별칭  # AS 생략가능 
WHERE 조건절;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건에 맞는 대상자 선정 후 요약할 때의 FROM절 하위 쿼리는 하위 쿼리를 작성한 후 테이블 별칭을 필수로 줘야한다. 만약 별칭을 주지 않았다면 에러가 발생한다. 이때 AS 키워드는 생략이 가능하다.&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;/p&gt;
&lt;pre id=&quot;code_1705304460337&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# FROM절의 하위 쿼리 - 테이블 조인을 할 때
SELECT 별칭1.열이름1, 별칭2.열이름2
FROM 테이블명1 (AS) 별칭1 LEFT OUTER JOIN
(SELECT 열이름1, 열이름2
FROM 테이블명2
WHERE 조건절) (AS) 별칭2  # AS 생략 가능
ON 별칭1.KEY = 별칭2.KEY;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FROM절의 하위 쿼리는 위 코드의 SQL문법 구조를 가지고 있다는 것을 확인하면 된다.&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;아래는 FROM절의 하위 쿼리에 대한 예제를 통해 간단히 알아본다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;611&quot; data-origin-height=&quot;416&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KlaQ0/btsDrl0rbEe/LECokV36LkjShpONyxhzx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KlaQ0/btsDrl0rbEe/LECokV36LkjShpONyxhzx0/img.png&quot; data-alt=&quot;예제 - CARD_ACCT 테이블 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KlaQ0/btsDrl0rbEe/LECokV36LkjShpONyxhzx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKlaQ0%2FbtsDrl0rbEe%2FLECokV36LkjShpONyxhzx0%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;416&quot; data-origin-width=&quot;611&quot; data-origin-height=&quot;416&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;예제 - CARD_ACCT 테이블 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;287&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIB8Zk/btsDrg5HJ44/UWaoehmwBWyJv7Xy1ke43k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIB8Zk/btsDrg5HJ44/UWaoehmwBWyJv7Xy1ke43k/img.png&quot; data-alt=&quot;예제 CUST_PARTY 테이블 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIB8Zk/btsDrg5HJ44/UWaoehmwBWyJv7Xy1ke43k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIB8Zk%2FbtsDrg5HJ44%2FUWaoehmwBWyJv7Xy1ke43k%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;506&quot; height=&quot;287&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;287&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;예제 CUST_PARTY 테이블 구조&lt;/figcaption&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;CARD_ACCT 테이블과 CUST_PARTY라는 테이블 데이터이다. 데이터 값을 쉽게 확인하기 위해 엑셀로 불러온 것이다. 이러한 테이블 데이터를 통해서 FROM절 하위 쿼리의 예시 코드를 작성해본다.&lt;/p&gt;
&lt;pre id=&quot;code_1705305270927&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# CUST_ACCT, CUST_PARTY 테이블 이용해 현재 살아있는 신용카드 보유 고객과 미보유 고객 수 나타냄
SELECT 
    CASE WHEN TMP2.SSN IS NOT NULL THEN 'O' ELSE 'X' END AS CC_HOLDER,
    SUM(CASE WHEN TMP2.SSN IS NOT NULL THEN 1 ELSE 0 END) AS CNT
FROM CUST_PARTY TMP1
LEFT OUTER JOIN (
    SELECT DISTINCT SSN
    FROM CARD_ACCT
    WHERE CLOSE_DT IS NULL
      AND CC_GRADE IN ('1', '2')
) TMP2 ON TMP1.SSN = TMP2.SSN
GROUP BY CC_HOLDER;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드를 하나씩 살펴보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 FROM절에소 CUST_ID를 TMP1으로 지정하며 LEFT OUTER JOIN 외부 조인을 수행하는데 외부 조인을 수행하는 테이블을 하위 쿼리방식으로 CARD_ACCT의 SSN을 들고오는데 CLOSE_DT가 NULL값이고, CC_GRADE가 1 또는 2인 경우를 들고온다. 그 후 TMP1의 SSN과 TMP2의 SSN을 외부 조인으로 연결시켜 준 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 SELECT 구문에 있는 것을 보면 CASE WHEN 구문으로 TMP2.SSN이 NULL값이 아니면 O, NULL값이면 X를 줘 CC_HOLDER에 넣고, TMP2.SSN이 NULL값이 아니면 1, NULL값이면 0을 넣고 SUM함수로 더해 CNT로 지정하면서 신용카드 보유 고객과 미보유 고객 수를 나타내주었다. 결과값은 이렇게 나올 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;147&quot; data-origin-height=&quot;78&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5l70U/btsDsWZ73lC/3eepoFm4kNejKkGtLKKW51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5l70U/btsDsWZ73lC/3eepoFm4kNejKkGtLKKW51/img.png&quot; data-alt=&quot;예시 코드 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5l70U/btsDsWZ73lC/3eepoFm4kNejKkGtLKKW51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5l70U%2FbtsDsWZ73lC%2F3eepoFm4kNejKkGtLKKW51%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;147&quot; height=&quot;78&quot; data-origin-width=&quot;147&quot; data-origin-height=&quot;78&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;예시 코드 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 하위 쿼리에서 DISTINCT를 사용했는데, 그 이유로는 CARD_ACCT의 SSN에는 중복값이 존재하기 때문에 제거를 하지 않으면 중복 값이 이중으로 붙기 때문에 제거를 수행한 것이다.&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;2. WHERE 조건절의 하위 쿼리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WHERE 조건절에서 하위 쿼리는 IN 연산자와 함께 쓰인다. 단일 결과값인 경우는 '='를 사용할 수 있지만 결과값이 단일이 아니면 사용할 수 없으므로, IN 연산자를 통해 다중 결과값을 가지게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 IN을 사용한 WHERE 조건절의 하위 쿼리 코드 문법이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705306780400&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# IN을 사용한 WHERE 조건절의 하위 쿼리 문법 구조
SELECT 열이름1, 열이름2
FROM 테이블명1
WHERE 열이름 IN (SELECT 열이름 FROM 테이블명2 WHERE 조건절);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 WHERE 조건절의 하위 쿼리는 특정 세그먼트만 추출할 때 유용하게 사용된다.&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;FROM 하위 쿼리 예시에 사용한 테이블 데이터를 그대로 사용해 WHERE 조건절의 하위 쿼리에 대해서 예시문제를 풀어본다.&lt;/p&gt;
&lt;pre id=&quot;code_1705306961420&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# CUST_ACCT. CUST_PARTU 테이블 이용해 현재 살아있는 신용카드 보유 고객의
# 주민등록번호, 이름, 아이디, 자택번호 및 휴대폰 번호 출력
SELECT *
FROM CUST_PARTY
WHERE SSN IN (SELECT DISTINCT SSN
			FROM CARD_ACCT
            WHERE CLOSE_DT IS NULL
            	AND CC_GRADE IN ('1', '2'));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드를 자세히 살펴보면 CUST_PARTY의 모든 열을 들고오고 조건으로 SSN IN (~~)를 통해 조건을 하위 쿼리를 활용해 조건을 주었다. 하위 쿼리의 조건을 보면 CARD_ACCT에서 중복을 제거한 SSN을 들고오는데, CLOSE_DT가 NULL값인 것과 CC_GRADE가 1 또는 2인 것을 들고오라는 것이다. 이러한 하위 쿼리 조건을 CUST_PARTY에 적용을 한 것이다. 결과는 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;454&quot; data-origin-height=&quot;76&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bufdQ5/btsDxwTM2Pu/1LzuzTLZnPBzu9StAfM3Nk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bufdQ5/btsDxwTM2Pu/1LzuzTLZnPBzu9StAfM3Nk/img.png&quot; data-alt=&quot;WHERE조건절 하위 쿼리 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bufdQ5/btsDxwTM2Pu/1LzuzTLZnPBzu9StAfM3Nk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbufdQ5%2FbtsDxwTM2Pu%2F1LzuzTLZnPBzu9StAfM3Nk%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;454&quot; height=&quot;76&quot; data-origin-width=&quot;454&quot; data-origin-height=&quot;76&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;WHERE조건절 하위 쿼리 결과&lt;/figcaption&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;/p&gt;
&lt;pre id=&quot;code_1705307461930&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1단계
SELECT DISTINCT SSN
FROM CARD_ACCT
WHERE (CLOSE_DT IS NULL
	AND CC_GRADE IN ('1', '2'));
    
# 2단계
SELECT * FROM CUST_PARTY
WHERE SSN IN ('5705121111000', '8204073333111');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 두 단계를 나눠서 해야할 일을 IN을 사용한 WHERE 조건절의 하위 쿼리를 통해서 한번에 처리를 할 수 있다.&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;만약 단일 행을 구하는 것이면 IN연산자 대신 '='를 사용할 수 있다. 아래는 예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705307610204&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# WHERE 하위 쿼리 : 단일 행(1개의 값만 찾는 것)인 경우
SELECT *
FROM CUST_PARTY
WHERE SSN = (SELECT DISTINCT SSN
		FROM CARD_ACCT
        WHERE SSN = '6508112222333');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SSN이 2개 이상이 아닌 딱 하나의 값을 기준으로 찾는 것이기 때문에 부등호 '=' 사용이 가능한 것이지, 2개 이상의 값을 찾을려면 IN연산자로 무조건 사용해야한다.&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;● 데이터 조작(DML: Data Manipulation Language)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터는 하위 쿼리에 사용했던 데이터인 CUST_PARTY 테이블 데이터를 사용한다.&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;1. 데이터 삽입&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 SQL 내부에 새로 추가하기 위해서 사용하는 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 삽입은 완전한 행 삽입, 열 이름과 함께 완전한 행 삽입, 부분 행 삽입, SQL문장 결과를 삽입으로 4가지가 있다. 아래는 각 데이터 삽입에 대한 코드 문법이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705319878035&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 완전한 행 삽입
INSERT INTO 테이블명
VALUES(값1, 값2, 값3);

# 열이름과 함께 완전한 행 삽입
INSERT INTO 테이블명(열이름1, 열이름2, 열이름3)
VALUES(값1, 값2, 값3);

# 부분 행 삽입
INSERT INTO 테이블명(열이름1, 열이름3)
VALUES(값1, 값3);

# SQL 문장 결과를 삽입
INSERT INTO 테이블명1(열이름1, 열이름2, 열이름3)
SELECT 열이름1, 열이름2, 열이름3 FROM 테이블명2 WHERE 조건절;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 테이블 내에 적재하기 위해 이러한 방법을 사용한다. 위 4가지 방법 중 열 이름을 지정하지 않고 삽입하는 방법은 코딩을 짧게 해도 되는 장점이 존재지만, 데이터를 삽입하는 값의 순서가 변경될 경우 데이터를 적재하는 테이블이 망가질 수 있는 위험이 존재하기 때문에 조심하거나, 열 이름을 지정해서 값을 적재하는 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 데이터 삽입에 대한 예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705320229009&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 열 이름 사용하지 않고 행 전체 입력
INSERT INTO CUST_PARTY
VALUES('5508151111222', 'MJ YOO', '8828', '02-312-1111', '010-1122-1111');

# 열 이름을 사용해 행 전체 입력하기
INSERT INTO CUST_PARTY (SSN, PARTY_NM, CUST_ID, TEL_NO, MOBILE_NO)
VALUES('5508151111222', 'MJ YOO', '8828', '02-312-1111', '010-1122-1111');

# 열 이름 사용해 행 전체 입력 &amp;amp; MOBILE_NO는 NULL값 허용 열(부분 행 삽입)
INSERT INTO CUST_PARTY (SSN, PARTY_NM, CUST_ID, TEL_NO)
VALUES('5508151111222', 'MJ YOO', '8828', '02-312-1111');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드처럼 데이터 값을 삽입할 수 있으며, 만약 데이터 값 중 NULL값으로 넣고 싶으면 열 이름과 값을 지정하지 않으면 NULL값으로 지정이 된다.&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;2. 데이터 삭제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터가 오래되어 데이터가 필요없어질 경우 데이터를 삭제를 수행할 수도 있다. 데이터 삭제에 대한 구문은 2가지가 존재하는데 테이블의 모든 행을 삭제하는 방법과 테이블의 부분적인 행만 삭제하는 방법으로 나눠진다. 아래는 데이터 삭제에 대한 두가지 코드 구문이다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1705320935211&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 테이블의 모든 행 삭제
DELETE FROM 테이블명;

# 테이블의 부분 행 삭제
DELETE FROM 테이블명
WHERE 조건절;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 삭제를 위한 DELETE절을 사용할 때에는 주의를 요해야한다. 그 이유로는 SQL에는 실행한 내용을 취소할 수 있는 기능이 없기 때문에 테이블 데이터를 실수로 삭제를 했다면, 되돌릴 방법은 SQL자체를 ROLLBACK을 시켜 이전 시간으로 돌리는 것 뿐이다. 이러한 ROLLBACK은 TCL(Transaction Control Language)의 하나이지만, 개발자가 직접적으로 TCL을 사용을 잘 하지 않으므로 설명을 생락한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 데이터 삭제에 대한 예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705321529189&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 테이블 전체 삭제
DELETE FROM CUST_PARTY

# 테이블의 부분 행 삭제
DELETE FROM CUST_PARTY
WHERE PARTY_NM IN ('AR KIM', 'JH KIM');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드 중 테이블의 부분 행 삭제를 보면 CUST_PARTY 테이블 데이터 중 PARTY_NM이 'AR KIM' 또는 'JH KIM'인 행만 삭제한다는 것이다. 이렇게 WHERE을 통해 조건을 줘 삭제해야하는 지정해서 삭제할 수 있다.&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;3. 데이터 수정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 수정은 테이블에 적재되어 있는 데이터 중 전화번호가 변경되었다거나, 이름이 바뀌었다는 등 정보가 변경되는 경우가 존재한다. 이때 사용하는 방법이 데이터 수정 방법이다. 데이터 수정 또한 모든 행의 데이터를 수정하는 방법과 특정한 행의 데이터를 수정하는 방법이 있다. 아래는 데이터 수정에 대한 코드 구문과 예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705321833589&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 모든 행의 데이터 수정
UPDATE 테이블명
SET 열이름 = 변경할 값;

# 특정한 행의 데이터 수정
UPDATE 테이블명
SET 열이름 = 변경할 값
WHERE 조건절;

# 모든 행의 데이터 수정 예시 코드
UPDATE CUST_PARTY
SET CUST_ID = '1111';

# 특정한 행의 데이터 수정 예시 코드
UPDATE CUST_PARTY
SET MOBILE_NO = '010-9988-5555'
WHERE SSN = '901103444111';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시코드 중 모든 행의 데이터 수정 예시 코드를 보면 CUST_PARTY의 CUST_ID를 1111로 전체 데이터가 변경이 되는 것이다. 그 아래에 있는 특정한 행의 데이터 수정 예시 코드는 WHERE을 통해 조건을 줘 CUST_PARTY에 있는 MOBILE_NO를 010-9988-5555로 변경하는데 모두 변경하는 것이 아닌 SSN이 9011034444111인 사람만 변경하라는 코드 구문이다. 이를 통해서 만약 적재된 테이블 데이터를 바꿔야 한다면 이러한 UPDATE 구문을 사용해야한다.&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;● 테이블 조작(DDL: Data Definition Language)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 테이블 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블을 생성할 때는 CREATE TABLE 문법을 사용하며, 새로 생성할 테이블 이름, 열 이름, 데이터 형식을 지정해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 테이블 생성에 대한 코드 구문이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705322703000&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 일반적인 테이블 생성 방법
CREATE TABLE 생성할 테이블 명
(
열이름 데이터 형식(크기) NOT NULL,
열이름2 데이터 형식(크기) PRIMARY KEY,
열이름3 데이터 형식(크기) NOT NULL REFERENCES 테이블1(테이블1의 Primary key),
열이름4 데이터 형식(크기) NOT NULL DEFAULT 1,
);

# 하위 쿼리에 의해 검색된 테이블과 동일한 구조로 테이블 생성
CREATE TABLE 생성할 테이블명 AS
SELECT 열이름, 열이름2 FROM 복사할 테이블명;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 테이블 생성 방법에 나온 옵션에 대해서 살펴본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- NOT NULL 조건: 열 값에 NULL값을 허용하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- PRIMARY KEY: 열 중 고유값인 기본키로 지정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- REFERENCES 조건: 뒤에 있는 테이블1(테이블1의 기본키)와 연결된 외래키로 지정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- DEFAULT 1: 만약 NULL값이 발생하면 NULL 대신 1을 집어넣는다. 뒤에 1 대신 2로 지정하면 NULL값 대신 2를 집어넣는다.&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;- CHARACTER(n) 또는 CHAR(n): 고정 길이 문자 데이터, 고정폭 n - 문자열로 필요한 만큼 공백으로 채워짐&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- NATIONAL VARYING(n) 또는 NCHAR(n): CHAR타입과 기본적으로 같은 공간 관리 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CHARACTER VARYING(n) 또는 VARCHAR(n): n문자의 최대 크기를 가진 가변폭 문자열, 입력되는 문자 길이가 정의된 공간 길이보다 적더라도 나머지를 공간을 여백으로 채우지 않고 필요한 공간만 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- NVARCHAR(n): 가변폭 NCHAR(n) 문자열&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- BIT: 단일 비트값 / - NUMERIC(p, s) 또는 DECIMAPL(p, s): p는 전체 자리값, s는 소수점 이하 자릿수 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- FLOAT: 실수 값&amp;nbsp; /&amp;nbsp; - INTEGER 또는 INT: 숫자 저장할 수 있는 4Byte 정수값&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- DATE: 날짜값&amp;nbsp; /&amp;nbsp; - TIME: 시간값&amp;nbsp; /&amp;nbsp; - TIMESTAMP: DATE와 TIME이 하나의 변수로 결합된 형태&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;/p&gt;
&lt;pre id=&quot;code_1705323451852&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# CUST_PARTY 테이블 생성
CREATE TABLE CUST_PARTY (
	SSN CHAR(13) PRIMARY_KEY,
	PARTY_NM VARCHAR(20) NOT NULL,
	CUST_ID CHAR(4) NOT NULL,
	TEL_NO VARCHAR(20) NULL,
	MOBILE_NO VARCHAR(20) NULL
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CUST_PARTY 테이블을 생성한다. SSN은 문자열 길이 13에 기본키 지정하고 PARTY_NM은 가변 문자열 길이 20 지정에 NOT NULL로 결측값이 없게 만들었고, CUST_ID는 문자열 길이 4로 NOT NULL 조건을 달았다. 그 후 TEL_NO는 가변길이 문자열 20을 지정하고 NULL 결측값을 허용하고, MOBILE_NO도 TEL_NO와 마찬가지로 가변길이 문자열 20과 NULL값을 허용하게 하고 CUST_PARTY라는 테이블을 생성한 것이다.&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;2. 테이블 변경 및 삭제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블 변경 및 삭제는 테이블에 새로 열을 추가를 해야하거나 아예 테이블 자체가 필요 없어질 경우 등 테이블 자체와 테이블 내부 추가해야하는 열이 새로 존재하는 경우 사용한다. 아래는 테이블 변경 및 삭제에 대한 코드 구문이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705324081854&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 테이블 변경(열 추가)
ALTER TABLE 수정할 테이블명
ADD (추가할 열 이름데이터 형식(크기));

# 테이블 변경(데이터 구조 변경)
ALTER TABLE 수정할 테이블명
MODIFY (변경할 열 이름 변경할 데이터 형식(크기));

# 테이블명 변경
RENAME 변경 전 테이블명 TO 변경 후 테이블명;

# 테이블 삭제
DROP TABLE 삭제할 테이블명;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블 변경 및 삭제에는 위 4가지 정도가 존재한다. 아래에 이어서 테이블 변경 및 삭제에 대한 예시 코드를 작성한다.&lt;/p&gt;
&lt;pre id=&quot;code_1705324546078&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 테이블 변경(열 추가) - CUST_PARTY에 대한 열 추가: 나이(AGE)를 추가하기로 함
ALTER TABLE CUST_PARTY
ADD (AGE CHAR(3));

# 테이블 변경(데이터 구조 변경) - CUST_PARTY의 데이터 구조 변경: CUST_ID를 VARCHAR(5)로 변경
ALTER TABLE CUST_PARTY
MODIFY (CUST_ID VARCHAR(5));

# 테이블명 변경: CUST_PARTY를 CUST_CELEBRATE로 변경
RENAME CUST_PARTY TO CUST_CELEBRATE

# 테이블 삭제: 변경한 CUST_CELEBRATE를 테이블 전체 삭제
DROP TABLE CUST_CELEBRATE&lt;/code&gt;&lt;/pre&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;이때 자세히 보면 DELETE와 DROP 둘다 삭제를 한다는 공통점이 존재하는데 이 둘의 차이는 DELETE문으로 테이블을 지정하면 테이블 자체가 삭제되는 것이 아닌 테이블 내부에 있는 데이터들만 전체 삭제가 되는 것이다. 하지만 DROP문을 통해 테이블을 지정하면 테이블 내부에 있는 데이터뿐만 아니라 테이블 자체도 삭제가 이루어지는 차이가 존재한다.&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;이렇게 SQL에 대한 기본적인 코드 정리를 해보았다. 이러한 기초를 통해 내가 원하는 데이터를 출력하고 사용하는 방법에 대해서 배우게 되었기 때문에 이를 실무에 잘 적용할 수 있도록 정진하겠다.&lt;/p&gt;</description>
      <author>DataKwon</author>
      <guid isPermaLink="true">https://koy0911.tistory.com/11</guid>
      <comments>https://koy0911.tistory.com/11#entry11comment</comments>
      <pubDate>Mon, 15 Jan 2024 22:19:32 +0900</pubDate>
    </item>
    <item>
      <title>기초적인 SQL 코드 및 정리</title>
      <link>https://koy0911.tistory.com/10</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 분석가라면 직접 DB에서 원하는 데이터를 뽑아내서 사용을 할 줄 알아야 할 때가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 DB중 SQL을 많이 사용을 한다. SQL을 통해 데이터 적재나 구조를 직접 짤 필요는 없지만 언제든지 내가 원하는 데이터를 가져다 쓸 수 있게 하기 위해서는 SQL에 대한 기초 코드는 파악해두는 것이 좋을 것이다.&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;● SQL이란?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Structured Query Language(구조화된 질의 언어)의 약자로, 관계형 데이터베이스 관리 시스템(RDBMS)에서 데이터를 관리하고 처리하기 위해 사용되는 표준화된 언어이다. SQL은 데이터베이스에서 데이터를 조회, 삽입, 수정, 삭제 등 다양한 작업을 수행하는데 사용된다.&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;●DBMS의 특성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 실시간 접근성(Real-timepricessing): 컴퓨터가 접근할 수 있는 저장 장치에서 관리되는 데이터베이스는 지속적이고 비정형적인 질의에 대하여 실시간 처리가 가능해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 계속적인 변화(Continuous evolution): 데이터베이스의 상태는 동적이며, 기존의 데이터베이스가 존재한다면 그 데이터베이스에 새로운 데이터 삽입, 기존 데이터 삭제, 갱신 등의 변화를 주어 정확한 데이터를 유지해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 동시 공용(Concurrent sharing): 데이터베이스는 다수의 사용자가 동시에 각자 원하는 데이터에 접근하여 이용할 수 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 내용에 의한 참조(Contents reference): 데이터베이스 환경에서 데이터의 참조는 레코드의 주소나 위치에 의해서가 아니라 사용자가 요구하는 데이터의 내용, 즉 데이터가 가지고 있는 값에 따라 참조된다.&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;● SQL의 종류&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. DDL(Data Definition Language): 데이터와 그 구조를 정의하는 언어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 1.1 CREATE: 데이터베이스 테이블 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 1.2 DROP: 데이터베이스 테이블 삭제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 1.3 ALTER: 기존 데이터베이스 테이블 재정의&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DDL코드 구문&lt;/p&gt;
&lt;pre id=&quot;code_1705060439576&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# CREATE 구문
CREATE TABLE 테이블명 (
	열1 데이터_유형,
    열2 데이터_유형,
    .....
);

CREATE TABLE employees (
	employee_id INT,
    employee_name VARCHAR(50)
);   							# CREATE 예시

# DROP 구문
DROP TABLE 테이블명;

DROP TABLE employees;  # DROP 예시

# ALTER 구문
ALTER TABLE 테이블명
ADD COLUMN 새로운_열 데이터_유형;

ALTER TABLE employees
ADD COLUMN hire_date DATE;   # ALTER 예시&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. DML(Data Manipulation Language): 데이터 검색과 수정 등의 처리를 위한 언어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 2.1 INSERT: 테이블에 데이터 삽입/입력&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 2.2 DELETE: 테이블의 데이터 삭제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 2.3 UPDATE: 기존 테이블 안의 데이터 수정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 2.4 SELECT: 테이블 내 데이터 검색&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DML코드 구문&lt;/p&gt;
&lt;pre id=&quot;code_1705060192443&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# INSERT 구문
INSERT INTO 테이블명 (열1, 열2, ...)
VALUES (값1, 값2, ...);

INSERT INTO employees (employee_name, salary)
VALUES ('John Doe', 50000);    # INSERT 예시

# DELETE 구문
DELETE FROM 테이블명
WHERE 조건;

DELETE FROM employees
WHERE employee_name = 'John Doe';  # DELETE 예시

# UPDATE 구문
UPDATE 테이블명
SET 열1 = 값1, 열2 = 값2, ...
WHERE 조건;

UPDATE employees
SET salary = 55000
WHERE employee_name = 'John Doe';  # UPDATE 예시

# SELECT 구문
SELECT 열1, 열2, ...
FROM 테이블명
WHERE 조건;

SELECT employee_name. salary
FROM employees
WHERE salary &amp;gt; 50000;  # SELECT 예시&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;3. DCL(Data Control Language): 데이터베이스 사용자의 권한 제어를 위해 사용되는 언어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 3.1 GRANT: 테이블에 권한 부여&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 3.2 REVOKE: 부여한 권한 취소/회수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DCL 코드 구문&lt;/p&gt;
&lt;pre id=&quot;code_1705060145722&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# GRANT 코드 구문
GRANT 권한 ON 객체 TO 사용자 또는 역할;
GRANT SELECT, INSERT ON employees TO user1;  # GRANT 예시

# REBOKE
REVOKE 권한 ON 객체 FROM 사용자 또는 역할;
REVOKE INSERT ON employees FROM user1;  # REVOKE 예시&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;4. TCL(Transaction Control Language): 트랜잭션을 제어하기 위한 언어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 4.1 COMMIT: 트랜잭션의 작업 확정하고, 데이터베이스에 변경사항을 영구적으로 반영&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 4.2 ROLLBACK: 트랜잭션의 작업 취소하고, 이전 상태로 되돌림&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCL 코드 구문&lt;/p&gt;
&lt;pre id=&quot;code_1705060025253&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# COMMIT 명령어 구문 &amp;amp; 예시
COMMIT;
# ROLLBACK 명령어 구문 &amp;amp; 예시
ROLLBACK;&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;모든 SQL 코드의 끝은 ' ; ' 표시로 끝내야한다.&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;위에 간단한 SQL의 종류 별 예시코드를 확인해보았다. 이제 본격적으로 SQL기초 코드에 대해서 알아본다.&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;● SQL 기초&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터 가져오기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot; SELECT 열 이름 FROM 테이블명; &quot; 이런식으로 테이블에 적재된 데이터 중, 지정된 열 이름의 데이터 전부를 들고오는 것이다. 만약 여러 열을 들고올려면&amp;nbsp; &quot; SELECT 열 이름1, 열 이름2,... FROM 테이블명; &quot; 처럼 열을 여러개 지정하면 된다. 만약 테이블에 존재하는 모든 열을 들고올려면 애스터리스트 문자인 * 를 사용하면 된다. &quot; SELECT * FROM 테이블명; &quot; 을 수행하면 테이블에 존재하는 모든 데이터를 들고올 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 간단한 예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705061583342&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# CLERK 테이블에 id, staff_nm, dep_nm, gender의 데이터 열 전체를 불러오는 SQL 코드
SELECT id, staff_nm, dep_nm, gender FROM CLERK;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;가져온 데이터는 무작위 정렬이 되는데, 만약 특정 열 기준으로 오름차순, 내림차순으로 정렬을 하고 싶다면 ORDER BY절을 사용하면 된다. 이러한 ORDER BY절은 다음에 배울 다른 조건들보다 맨 마지막에 사용되어야 한다, 이는 이후 SQL구문을 사용할 때 알아보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 ORDER BY절의 예시구문이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705061814433&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# id, staff_nm, dep_nm, gender를 CLERK 테이블에서 뽑고 id를 기준으로 오름차순 정렬
SELECT id, staff_nm, dep_nm, gender FROM CLERK
ORDER BY id;
#id 말고 위 코드에 지정한 열 위치를 기준으로도 사용할 수 있다.
SELECT id, staff_nm, dep_nm, gender FROM CLERK
ORDER BY 1;  # id를 기준으로 오름차순 정렬, 3을 사용하면 dep_nm 기준 오름차순 정렬 수행&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ORDER BY절은 ASC와 DESC가 존재하는데, 기본값으로 ASC인 오름차순을 수행하며, 내림차순을 수행할려면 &quot; ORDER BY id DESC; &quot; 처럼 직접 입력을 해야한다. 또한 정렬 기준을 하나만 사용할 수 있는 것이 아닌 여러개를 정렬 기준으로 사용할 수 있다.&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;● SELECT문에 추가적으로 필요한 키워드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- DISTINCT 키워드: 중복이 있는 데이터를 중복없이 출력&lt;/p&gt;
&lt;pre id=&quot;code_1705062450028&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# DISTINCT 구문 , 열에 대한 데이터의 중복을 없애고 출력함
SELECT DISTINCT 열 이름 FROM 테이블명;

# 복수의 DISTINCT 사용 , 열 이름1, 열 이름2를 집합으로 중복 없애고 출력함
SELECT DISTINCT 열 이름1, 열 이름2 FROM 테이블명;

# DISTINCT 예시: position, grade 두개를 집합으로 중복값을 없애서 출력
SELECT DISTINCT position, grade FROM EMP;&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;- ALIAS(별칭) : AS: 데이터의 열 이름을 바꿔서 출력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AS를 사용하는 방법, 인용부호( &quot; &quot; ) 를 사용하는 방법, 인용부호 ( &quot; &quot; ) + AS 사용하는 방법으로 3가지가 있지만 주로 첫번째 방법인 AS를 사용하는 방법이 제일 편하고 간단하다. 아래는 ALIAS를 사용하는 예시이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705062836095&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# ALIAS : AS 예시
# id를 clerk_id로 열 이름을 지정하고 grade를 perf로 열 이름을 변경해서 데이터를 출력한다.
SELECT id AS clerk_id, position, party_nm, grade AS perf
FROM EMP;&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;● WHERE 조건절을 활용한 데이터 조건 주기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 테이블에서 특정한 조건을 만족하는 데이터를 추출하여 나타낼때 특정한 조건 주는 조건절이 WHERE 조건절이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 숫자형 데이터 조건 주기: SELECT 열이름1, 열이름2 FROM 테이블명 WHERE 비교할 열 = 숫자;&amp;nbsp; 형식으로 작성하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 문자/날짜형 데이터 조건 주기: SELECT 열이름1, 열이름2 FROM 테이블명 WHERE 비교할 열 이름 = '문자';&amp;nbsp; 형식으로 작성하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 WHERE 조건절 예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705065524225&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 숫자형 데이터 조건 주기
SELECT id, cnrt_no, cnrt_amt
FROM INS_INFO
WHERE cnrt_amt &amp;gt;= 1000000;  # INS_INFO에서 id, cnrt_no, cnrt_amt 출력 -&amp;gt; cnrt_amt가 100만 이상만

# 문자형 데이터 조건 주기
# id, cnrt_dt, prdt_nm을 INS_INFO에서 출력 -&amp;gt; prdt_nm이 자동차 보험인 것만 and id기준 오름차순 정렬
SELECT id, cnrt_dt, prdt_nm
FROM INS_INFO
WHERE prdt_nm = '자동차 보험'
ORDER BY id;

# 날짜형 데이터 조건 주기
# id, cnrt_dt, prdt_nm을 INS_INFO에서 출력 -&amp;gt; cnrt_dt가 20130416 이후인 데이터만 출력
SELECT id, cnrt_dt, prdt_nm
FROM INS_INFO
WHERE cnrt_dt &amp;gt;= '20130416';&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;※ 데이터에 NULL값(결측값)이 존재할 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- NULL값인 행을 찾는 경우 IS NULL을 사용하고 NULL값이 아닌 행을 찾는 경우는 IS NOT NULL을 사용한다. 또한 NULL값은 오름차순 또는 내림차순으로 정렬 시 가장 큰 값으로 분류된다.(오름차순 정렬 시 NULL값은 맨 아래로 내려감)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 IS NULL과 IS NOT NULL에 대한 예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705066392915&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# IS NULL 예시(WHERE 조건절은 불러오지 않지만 INS_INFO내에 있는 열을 조건에 쓸 수 있다.)
SELECT id, cnrt_no, cnrt_amt
FROM INS_INFO
WHERE cncl_dt IS NULL;

# IS NOT NULL 예시
SELECT id, cnrt_no, cnrt_amt
FROM INS_INFO
WHERE cncl_dt IS NOT NULL;&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;- NULL값을 처리하는 문법 COALESCE로 처리를 할 수 있다. COALESCE문은 SELECT로 열을 불러올 때 같이 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 COALESCE에 대한 예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705067110068&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# COLESCE 예시 -&amp;gt; COLESCE(cnrt_amt, 0)은 cnrt_amt가 결측값이면 0을 넣어준다.
SELECT id, cnrt_no, COLESCE(cnrt_amt, 0)
FROM INS_INFO
WHERE cnrt_no &amp;gt; 700000;

# 심화 코드
'''
CARD_TRAM_201311에 있는 cmf, party_nm과 pif_amt, inst_amt, cash_amt 가 null이면 0을 넣고
다 더해서 tot_amt라는 새로운 열을 만든다. 그 후 tot_amt를 내림차순으로 정렬한다.
'''
SELECT cmf, party_nm, (COALESCE(pif_amt, 0)
	+ COALESCE(inst_amt, 0)
    + COALESCE(cash_amt, 0)) AS tot_amt
FROM CARD_TRAN_201311
ORDER BY tot_amt DESC;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 데이터 중 NULL값이 존재할 시 처리하는 방법에 대해서 알아보았다, 이 이외에도 NULL값을 처리할 수 있는 함수들이 존재한다. 이러한 함수는 따로 다루지 않고 어떤 함수인지만 알아본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. ZEROIFNULL(열 이름): 해당 열에 NULL값 포함되면 숫자 0으로 바꾸는 함수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. NVL2(열 이름, 표현식1, 표현식2): 해당 열이 NULL이면 표현식 2의 값을 나타내고, NULL이 아니면 표현식1의 값을 나타냄&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;●논리연산자를 활용한 데이터 조건 주기 - WHERE 조건절에 두 개 이상의 조건을 주는 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 논리연산자 AND&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리연산자 AND는 특정한 조건들을 모두 만족하는 데이터를 추출하기위해 사용하는 연산자이며, 이러한 논리연산자 AND는 WHERE 조건절 뒤에 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AND연산자는 수학의 집합 개념 중 하나인 교집합과 같은 역할을 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 AND 논리연산자에 대한 예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705127921733&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# BRUNCH_INFO에서 brunch_no, brunch_nm, brunch_num, brunch_perf를 불러오는데
# brunch_num이 10 이상인 데이터와 brunch_perf가 C인 것만 들고 온다.
SELECT brunch_no, brunch_nm, brunch_num, brunch_perf
FROM BRUNCH_INFO
WHERE brunch_num &amp;gt;= 10 AND brunch_perf = 'C';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AND 논리연산자는 1개만 사용가능한 것이 아닌 2개 이상 여러개의 조건에도 사용할 수 있으며, AND를 조건 사이에 계속 이어서 사용하면 된다.&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;2. 논리연산자 OR&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리연산자 OR은 적어도 하나의 특정한 조건을 만족하는 데이터를 추출하기위해 사용하는 연산자이며, 이러한 논리연산자 OR은 AND와 마찬가지로 WHERE 조건절 뒤에 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OR연산자는 수학의 집합 개념 중 하나인 합집합과 같은 역할을 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 OR 논리연산자에 대한 예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705128128642&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# BRUNCH_INFO에서 brunch_no, brunch_nm, brunch_num, brunch_perf를 들고오는데,
# brunch_num이 8이상인 값 또는 brunch_perf가 A인 값을 불러온다.
SELECT brunch_no, brunch_nm, brunch_num, brunch_perf
FROM BRUNCH_INFO
WHERE brunch_num &amp;gt;= 8 OR brunch_perf = 'A';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OR 논리연산자는 AND와 마찬가지로 2개 이상 여러 조건에도 사용할 수 있다.&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;※ AND 논리연산자와 OR 논리연산자의 우선순위&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선순위로는 OR연산자보다 AND연산자를 우선적으로 처리한다. 만약 AND연산자보다 OR연산자를 먼저 처리하고 싶으면 해당 연산을 괄호로 묶어서 우선처리를 시켜주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 AND, OR 논리 연산자 우선순위에 대한 예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705128531696&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# BRUNCH_INFO에서 brunch_no, brunch_nm, brunch_num, brunch_perf, close_dt를 들고오는데,
# brunch_num이 8이 넘는것 또는 brunch_perf가 A인 것을 먼저 뽑은 후 close_dt가 NULL값이 아닌 것 출력
SELECT brunch_no, brunch_nm, brunch_num, brunch_perf, close_dt
FROM BRUNCH_INFO
WHERE (brunch_num &amp;gt;= 8 OR brunch_perf = 'A') AND close_dt IS NOT NULL;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드를 보면 괄호로 OR 논리연산자를 최우선으로 조건을 처리하고 그 다음으로 AND 연산자가 실행되도록 한 코드이다.&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;3. 논리연산자 IN&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IN 연산자는 여러 조건들 중 적어도 하나만 만족해도 출력한다. 즉, 여러개의 OR연산자를 하나로 묶은 것이라고 생각하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 IN 논리연산자에 대한 예시코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705128896709&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# BRUNCH_INFO에서 brunch_no, brunch_nm, brunch_num, brunch_perf를 들고오는데,
# brunch_no가 8 또는 10인것과 brunch_perf가 A 또는 B인 것을 들고와라
SELECT brunch_no, brunch_nm, brunch_num, brunch_perf
FROM BRUNCH_INFO
WHERE brunch_no IN (8, 10)
	AND brunch_perf IN ('A', 'B');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드를 보면 IN연산자 내에 있는 숫자나 문자는 OR연산자로 사용하는 것 처럼 8 또는 10, A 또는 B라는 뜻을 가지고 있다. 한마디로 여러개의 OR 논리연산자를 사용하는 것 보다 하나의 IN 연산자를 사용하는 것이 더 효율적으로 사용할 수 있을 것이다.&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;4. 논리연산자 NOT IN&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NOT IN 연산자는 IN연산자와 반대로 뒤에 있는 조건을 부정할 때 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 NOT IN 논리연산자에 대한 예시코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705129149824&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# BRUNCH_INFO에서 brunch_no, brunch_nm, brunch_num, brunch_perf를 들고오는데,
# brunch_no가 8 또는 10이 아닌 것과 brunch_perf가 A 또는 B가 아닌 것을 들고와라
SELECT brunch_no, brunch_nm, brunch_num, brunch_perf
FROM BRUNCH_INFO
WHERE brunch_no NOT IN (8, 10)
	AND brunch_perf NOT IN ('A', 'B');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 NOT IN 내부의 숫자나 문자는 IN 논리연산자와 같은 OR을 사용하지만, 8 또는 10이 아닌 것을 들고온다는 것이 IN 연산자와 다른 점이라고 볼 수 있다. 즉 걸러 내야할 값들을 걸러내고 출력할 때 NOT IN 연산자를 사용하면 효율적일 것이다.&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;※ IN 논리연산자와 NOT IN 논리연산자 지식&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IN, NOT IN 연산자는 OR 연산자보다 처리 속도가 빠르다. 즉, 데이터가 방대할 때 좀 더 빠르게 실행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IN, NOT IN 연산자 안에 다른 SELECT 문장을 사용할 수 있다. 이 내용은 뒤에 나올 하위 쿼리에서 언급한다.&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;● 텍스트를 활용한 데이터 조건 주기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. LIKE 연산자를 활용한 필터링&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 와일드 카드 문자( % : 숫자 0 또는 문자들을 대체하기 위해 사용,&amp;nbsp; _: 한 개의 단어를 대체하기 위해 사용됨)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LIKE 연산자는 조건 중 찾고 싶은 문자가 전부 기억이 나지 않을 때 LIKE 연산자와 와일드 카드 문자를 사용하여 필터링을 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 LIKE 연산자에 대한 예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705131186252&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1. 뒤에 나오는 문자들을 알 수 없는 경우
SELECT brunch_no, brunch_nm, brunch_name FROM INS_INFO WHERE brunch_name LIKE 'REA%'

# 2. 앞에 나오는 문자들을 알 수 없는 경우
SELECT brunch_no, brunch_nm, brunch_name FROM INS_INFO WHERE brunch_name LIKE '%REA'

# 3. 앞뒤에 나오는 문자들을 알 수 없는 경우
SELECT brunch_no, brunch_nm, brunch_name FROM INS_INFO WHERE brunch_name LIKE '%REA%'

# 4. 뒤에 나오는 문자를 알 수 없는 경우(한 글자만 모를 경우)
SELECT brunch_no, brunch_nm, brunch_name FROM INS_INFO WHERE brunch_name LIKE 'BREA_'

# 5. 앞에 나오는 문자를 알 수 없는 경우(한 글자만 모를 경우)
SELECT brunch_no, brunch_nm, brunch_name FROM INS_INFO WHERE brunch_name LIKE '_READ%'

# 6. 시작과 끝 문자만 아는 경우
SELECT brunch_no, brunch_nm, brunch_name FROM INS_INFO WHERE brunch_name LIKE 'B%D'

# 7. 특정 단어를 원하지 않는 경우
SELECT brunch_no, brunch_nm, brunch_name FROM INS_INFO WHERE brunch_name NOT LIKE '%REA%'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시 코드를 통해 LIKE 연산자를 어떻게 사용하는지에 대해서 간단하게 알아보았다.&lt;/p&gt;
&lt;p 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;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;필드 결합은 여러 개로 나눠진 필드를 하나로 묶어서 표현하고자 할 경우 사용한다. 이떄 SELECT문에 결합연산자 '||' 또는 '+'를 사용한다. SQL에서 주로 '||' 결합연산자를 사용한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;아래는 필드 결합에 대한 예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705132057142&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# '+'를 활용한 필드 결합
# id, name, city와 city값과 country값을 합친 열을 addr로 이름을 지정해 불러온다.
SELECT id, name, city, country, city + '('country')' as addr
FROM CUSTOMER;

# '||'를 활용한 필드 결합 ( + 대신 ||로 바꿔주면 된다.)
SELECT id, name, city, country, city || '('country')' as addr
FROM CUSTOMER;&lt;/code&gt;&lt;/pre&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;2. 공백 제거하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저장 된 데이터가 깨끗하지 않아 공백이 존재하거나, 데이터 끼리 결합을 해 파생 변수를 만들 때에도 공백이 발생 할 수 있기 때문에 공백을 제거할 줄 알아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공백 제거에는 오른쪽 공백을 제거하는 RTRIM, 왼쪽 공백을 제거하는 LTRIM, 양쪽 공백 제거하는 TRIM이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 TRIM에 대한 예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705132021700&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 양쪽 공백 제거
SELECT id, name, city, country, city ||'(' || TRIM(country) || ')' AS addr
FROM CUSTOMER;

# 오른쪽 공백 제거
SELECT id, name, city, LTRIM(country)
FROM CUSTOMER;

# 왼쪽 공백 제거
SELECT id, name, city, RTRIM(country)
FROM CUSTOMER;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 데이터에 공백이 존재한다면 이러한 LTRIM, RTRIM, TRIM을 통하여 처리를 수행할 수 있다.&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;● 기본 함수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 문자 함수: 변수를 특정한 형태로 변화시키는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적인 문자 함수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- LOWER: 모든 문자를 소문자로 변환&amp;nbsp; /&amp;nbsp; - UPPER: 모든 문자를 대문자로 변환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- LENGTH: 문자의 길이를 나타냄&amp;nbsp; /&amp;nbsp; - SUBSTR: 문자 값 중 원하는 길이만큼만 나타냄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- RTRIM: 문자열 오른쪽 공백 잘라냄&amp;nbsp; /&amp;nbsp; - LTRIM: 문자열 왼쪽 공백 잘라냄&amp;nbsp; /&amp;nbsp; - TRIM: 문자열 양쪽 공백 잘라냄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- REPLACE: 특정 문자열을 다른 문자열로 대체&amp;nbsp; /&amp;nbsp; - COALESCE: 조건에 따라 여러가지 값으로 치환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 문자 함수에 대한 예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705208031500&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# LOWER : 문자 소문자로 변환
SELECT id, name, LOWER(name) AS name_small
FROM VENDOR_INFO;

# UPPER: 문자 대문자로 변환
SELECT id, name, UPPER(name) AS name_big
FROM VENDOR_INFO;

# LENGTH: 문자의 자릿수를 세준다. - PYTHON의 COUNT함수랑 비슷하다.
SELECT id, name, LENGTH(name) AS name_cnt
FROM VENDOR_INFO;

# SUBSTR: 문자의 특정 부분만 출력 - SUBSTR(열 이름, 시작 위치, 자리수)
SELECT id, name, SUBSTR(name, 2, 3) AS name_str
FROM VENDOR_INFO;  # SUBSTR을 사용한 이름 중 2번쨰 문자부터 3글자를 뽑아냄&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. 숫자 함수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적인 숫자 함수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ROUND: 소수점 자릿수를 지정하여 반올림&amp;nbsp; /&amp;nbsp; - TRUNC: 해당 소수점 자리에서 잘라냄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- MOD(M, N): M을 N으로 나눈 나머지값 반환&amp;nbsp; /&amp;nbsp; - ABS: 값을 절대값으로 변환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SIGN: 숫자가 양수이면 1, 음수이면 -1, 0이면 0으로 변환&amp;nbsp; /&amp;nbsp; - SQRT: 제곱근을 나타냄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- COS: 지정한 값의 COS값을 나타냄&amp;nbsp; /&amp;nbsp; - SIN: 지정한 값의 SIN값을 나타냄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- PI: 지정한 값의 파이값을 나타냄&amp;nbsp; /&amp;nbsp; - TAN: 지정한 값의 TAN값을 나타냄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 숫자 함수에 대한 예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705208708415&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# ROUND: 지정한 소수점 자리 기준 반올림 / ROUND(열이름, 나타내고 싶은 소수점 자릿수)
SELECT prod_id, total_sales, ROUND(total_sales, 1) AS sale_rev
FROM PROD_SALES;  # 소수점 두번째 자리에서 반올림 -&amp;gt; 소수점 첫번째 자리까지 표현

# TRUNC(숫자, 소수자리수): 주어진 숫자를 정해진 소수 자릿수까지 자르거나 정수로 변환
SELECT prod_id, total_sales, TRUNC(total_sales, 1) AS sales_trunc
FROM PROD_SALES;  # total_sales를 소수점 첫번쨰 자리까지 자른 후 sales_trunc로 출력

# MOD(분자, 분모): 나머지를 구하는 함수
SELECT prod_id, total_sales, MOD(total_sales, sales_num) AS sales_balance
FROM PROD_SALES;  # total_sales를 sales_num으로 나누고 남은 나머지를 출력

# ABS(열이름): 열이름의 절대값 출력
SELECT prod_id, total_sales, econ_income, ABS(econ_income) AS abs_econ
FROM PROD_SALES;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숫자 함수 중 SIGN, COS, SIN, PI, TAN은 잘 사용되지 않는 숫자 함수이므로 예시 코드는 생략한다.&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;3. 날짜 함수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적인 날짜 함수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ADD_MONTHS: 지정한 날짜에 개월 수를 더한 값을 출력&amp;nbsp; /&amp;nbsp; -&amp;nbsp;SYSDATE: 현재 시스템 날짜 데이터 반환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- LAST_DAY: 해당 월의 마지막 날짜 반환&amp;nbsp; /&amp;nbsp; - MONTH_BETWEEN: 지정된 두 월 간 월 수 반환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 날짜 함수에 대한 예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705210827734&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# ADD_MONTHS(날짜 열, 더할 월 숫자)
SELECT id, birth_dt, ADD_MONTHS(birth_dt, 1) AS plus1_birth
FROM CLERK;

# SYSDATE: 현재 날짜와 시간 반환
SELECT id, birth_dt, SYSDATE AS current_date
FROM CLERK;

# MONTH_BETWEEN: 지정된 두 날짜의 월 간의 월 수를 반환
SELECT id, birth_dt, SYSDATE AS current_date, MONTH_BETWEEN(birth_dt, current_date) AS momt_diff
FROM CLERK;

# LAST_DAY: 해당 월의 마지막 날짜 변환
SELECT id, birth_dt, LAST_DAY(birth_dt) AS last_day_birth_month
FROM CLERK;&lt;/code&gt;&lt;/pre&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;● 함수 활용하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 숫자 데이터 요약하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;집계 함수 정리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- COUNT: 행의 수를 나타냄 -&amp;gt; NULL값 포함: COUNT(*), NULL값 제외: COUNT(열이름), 중복 제외: COUNT(DISTINCT 열이름)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SUM: 행의 합계 나타냄&amp;nbsp; /&amp;nbsp; - AVG: 행의 평균 나타냄&amp;nbsp; /&amp;nbsp; - MAX: 행의 최대값 나타냄&amp;nbsp; /&amp;nbsp; - MIN: 행의 최소값 나ㅏ냄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- STDENV: 행의 표준편차 나타냄&amp;nbsp; /&amp;nbsp; - VARIANCE: 행의 분산 나타냄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 집계 함수에 대한 예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705211490420&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# COUNT: 행의 수 출력
SELECT COUNT(*) AS cnt FROM STUD_SCORE;  # NULL값도 포함시켜 행의 수
SELECT COUNT(math_score) AS math_cnt FROM STUD_SCORE; # NULL값 포함 X 행의 수
SELECT COUNT(DISTINCT math_score) AS math_distinct_cnt FROM STUD_SCORE; # 중복 포함, NULL x 행 수

# SUM: 행의 값 합계 출력
SELECT SUM(math_score) AS sum_math FROM STUD_SCORE;

# AVG: 행의 값 평균 출력
SELECT AVG(music_score) AS avg_music FROM STUD_SCORE;

# MAX: 행의 값 중 최대값 출력
SELECT MAX(music_score) AS maximum_music FROM STUD_SCORE;

# MIN: 행의 값 중 최소값 출력
SELECT MIN(music_score) AS minimum_music FROM STUD_SCORE;

# STDENV: 행의 값 표준편차 출력
SELECT STDENV(math_score) AS std_math FROM STUD_SCORE;

# VARIANCE: 행의 값 분산 출력
SELECT VARIANCE(music_score) AS var_music FROM STUD_SCORE;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- COUNT함수는 데이터의 검증용으로 많이 사용: 테이블에 NULL값이나 중복값 있는지 눈으로 찾기 어렵기 때문에 COUNT함수를 활용해 쉽게 검증&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 집계 함수 사용하면(COUNT함수 제외) NULL값은 계산에서 무시: NULL값을 포함해 계산하고 싶다면 앞에서 배운 COALESCE함수를 이용해 치환 후 사용하면 된다.&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;2. 조건문 이해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CASE WHEN은 조건에 따른 결과값을 출력할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 CASE WHEN 구조와 예시이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705212100098&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# CASE WHEN 문장 구조
SELECT 열이름1,
	CASE WHEN [조건1] THEN [결과값1]
    WHEN [조건2] THEN [결과값2]
    ELSE [결과값3] END AS 새로운 열 이름
FROM 테이블명;

# CASE WHEN 문장 예시
SELECT id, job, current_sal, eng_score,
	CASE WHEN job = 'CLERK' AND eng_score &amp;gt;= 80
    	THEN current_sal * 1.07
    	WHEN job = 'CLERK' AND eng_score &amp;lt; 80
    	THEN current_sal * 1.06
    	WHEN job = 'OFFICER' AND eng_score &amp;gt;= 80
    	THEN current_sal * 1.05
    	WHEN job = 'OFFICER' AND eng_score &amp;lt; 80
    	THEN current_sal * 1.04
    	ELSE current_sal
    END AS next_sal
FROM STAFF_SAL;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 CASE WHEN 문장 예시는 STAFF_SAL에서 job, current_sal, eng_score를 불러오고 만약 job이 CLERK이고 영어점수가 80점 이상이면 current_sal이 7% 상승, CLERK이고 영어점수가 80점 미만이면 current_sal이 6% 상승, job이 OFFICER이고 영어점수가 80점 이상이면 current_sal 5%증가, OFFICER이고 영어점수가 80점 미만이면 4% 증가, 나머지는 current_sal 그대로 출력을 시키고 이러한 값이 저장된 열 이름을 next_sal로 지정해서 출력한다는 것이다. 이처럼 많은 조건에 따라 변경되는 값을 출력하고 싶을 때 CASE WHEN을 사용하면 좋을 것이다.&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>SQL 공부 및 연습</category>
      <author>DataKwon</author>
      <guid isPermaLink="true">https://koy0911.tistory.com/10</guid>
      <comments>https://koy0911.tistory.com/10#entry10comment</comments>
      <pubDate>Sun, 14 Jan 2024 15:08:26 +0900</pubDate>
    </item>
    <item>
      <title>Python시각화 패키지 - Seaborn</title>
      <link>https://koy0911.tistory.com/9</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 분석이나 데이터를 파악하기 위해서는 통계분석도 중요하지만 직관적으로 확인할 수 있는 시각화 패키지 또한 매우 중요하다. 이러한 시각화 패키지 중 Python Seaborn 시각화 코드에 대해서 살펴보겠다.&lt;/p&gt;
&lt;pre id=&quot;code_1704786038291&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
import numpy as np
import warnings
warnings.filterwarnings('ignore')
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
%config InlineBackend.figure_format = 'retina'

tip = sns.load_dataset('tips')
tip.head()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요 파이썬 패키지를 들고와준 후, 사용할 데이터는 간단하게 seaborn 패키지에서 제공해주는 tips 데이터를 사용할 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;316&quot; data-origin-height=&quot;141&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c0527F/btsC7qg6cDL/1zX0RlE0cHNPHHLiXZbb80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c0527F/btsC7qg6cDL/1zX0RlE0cHNPHHLiXZbb80/img.png&quot; data-alt=&quot;tip dataset&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c0527F/btsC7qg6cDL/1zX0RlE0cHNPHHLiXZbb80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc0527F%2FbtsC7qg6cDL%2F1zX0RlE0cHNPHHLiXZbb80%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;316&quot; height=&quot;141&quot; data-origin-width=&quot;316&quot; data-origin-height=&quot;141&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;tip dataset&lt;/figcaption&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;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;● swarmplot&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;swarmplot() 함수는 데이터의 분산까지 고려하여 데이터 포인트가 서로 중복되지 않도록 그린다. 이를 통해 데이터가 퍼져있는 정도를 입체적으로 볼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1704786638352&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# swarmplot 그리기 - time 범주에 따른 total_bill 분포플롯
sns.swarmplot(x = 'total_bill', y = 'time', data=tip, hue = 'sex')&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;540&quot; data-origin-height=&quot;385&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCEy2q/btsC88ADjOw/Ec1KIpvjeYwLKUkFRXa97K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCEy2q/btsC88ADjOw/Ec1KIpvjeYwLKUkFRXa97K/img.png&quot; data-alt=&quot;time에 따른 total_bill 분포 with 성별&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCEy2q/btsC88ADjOw/Ec1KIpvjeYwLKUkFRXa97K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCEy2q%2FbtsC88ADjOw%2FEc1KIpvjeYwLKUkFRXa97K%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;459&quot; height=&quot;327&quot; data-origin-width=&quot;540&quot; data-origin-height=&quot;385&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;time에 따른 total_bill 분포 with 성별&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위 그림을 통해 total_bill이 Lunch보다 Dinner가 많은 것을 알 수 있고, 여성은 대부분 Lunch시간에, 남성은 대부분 Dinner 시간에 식당 식사를 한다는 것을 파악할 수 있다.&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;이러한 swarmplot의 문제점으로는 개별 데이터에 대해서 데이터 포인트가 서로 중복되지 않도록 그리기 때문에 데이터의 양이 크면 클수록 실행 속도가 느려지고, 시각화가 원활하지 않다는 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;우리가 다루는 데이터의 크기는 매우 방대한 크기를 가지고 있기 때문에 이러한 swarmplot을 잘 사용하지 않고 전체적인 분포를 쉽게 파악가능한 boxplot이나 violinplot을 사용을 한다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;●Box Plot&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;데이터의 분포를 시각적으로 표현하는 시각화 방법, 데이터의 중앙값과 분산, 이상치를 쉽게 파악할 수 있도록 도와준다,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Box Plot는 상자(Box)와 수염(Whiskers), 이상치(Outliers)로 이루어져 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 상자: 데이터의 중간 50%와 상자의 아래 경계인 25% 백분위수, 상자의 상단 경계인 75%를 알려준다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 수염: 데이터의 전체 분포를 나타내며, BoxPlot에서 수염을 벗어나는 데이터는 통계적으로 이상치로 구분한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 이상치: 상자와 수염을 벗어나는 개별적인 데이터 포인트를 나타낸다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;아래는 Box Plot의 시각화 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1704790297570&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 성별에 따른 total_bill의 BoxPlot &amp;amp; 시간대 별 total_bill의 BoxPlot
sns.boxplot(x = 'sex', y = 'total_bill', data = tip, hue = 'time')&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;516&quot; data-origin-height=&quot;401&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/drnv1l/btsDfoh2f7t/xEvg9sdjGG6FyfeQAltHFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/drnv1l/btsDfoh2f7t/xEvg9sdjGG6FyfeQAltHFk/img.png&quot; data-alt=&quot;성별과 시간대에 따른 total_bill의 BoxPlot&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/drnv1l/btsDfoh2f7t/xEvg9sdjGG6FyfeQAltHFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdrnv1l%2FbtsDfoh2f7t%2FxEvg9sdjGG6FyfeQAltHFk%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;316&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;401&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;성별과 시간대에 따른 total_bill의 BoxPlot&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림을 보면, 상자와 선, 점이 있는데 상자에서 중앙의 선은 중위수를 뜻하고, 그 위 아래로 상단 경계 75%와 하단 경계 25%로 상자의 크기가 정해진 것이다. 선이 있는 구역은 수염을 칭하며 이러한 수염은 데이터의 전체 분포를 알려준다. 마지막으로 수염에서 벗어난 이상치는 점 형태로 표시가 되어 있으며 이러한 점들을 통해 이상치를 간접적으로 파악할 수 있는 것이다. 다만 이러한 BoxPlot의 이상치는 데이터의 통계적으로 정의된 기준에 따라 결정 되기 때문에 그 자체로는 실제로 문제가 있는 데이터를 나타내는 것이 아닐 수 있다. 그러므로 이상치를 처리할 때 주의가 필요하다.&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;●Violin Plot&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터의 분포를 표현하는 시각화 방법 중 하나로, 커널 밀도 추정을 기반으로 한다. 데이터의 분포를 표현하는 시각화 방법인 BoxPlot과 유사하지만 차이도 존재한다.&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;Box Plot과 Violin Plot 공통점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 중앙 경향성 표현: 두 시각화 방법은 모두 데이터의 중앙 경향성을 나타낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-사분위수 표현: 두 시각화 방법은 데이터 분포를 나타나는데에 있어 사분위수(Q1, Q3)를 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Box Plot과 Violin Plot 차이점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 분포 정보: BoxPlot은 데이터의 중간 50%를 나타내고 이상치 확인하는 데 중점을 두는 반면, Violin Plot은 커널 밀도 추정을 사용해 전체 데이터 분포를 그림으로 나타낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 가시성: Violin Plot이 Box Plot에 비해 데이터의 분포를 더 쉽게 이해할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이상치 표현: Violin Plot은 이상치를 명확하게 표현 하지 않는다.&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;아래는 Violin Plot의 시각화 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1704791247548&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 성별과 시간대에 따른 팁 분포 파악
sns.violinplot(x = 'sex', y = 'tip', data = tip, hue = 'time')&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;520&quot; data-origin-height=&quot;392&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3BSZN/btsDhhCTInl/L6U9kUDtPYgU4IqA50IeQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3BSZN/btsDhhCTInl/L6U9kUDtPYgU4IqA50IeQ1/img.png&quot; data-alt=&quot;성별과 시간대에 따른 팁 Violin Plot 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3BSZN/btsDhhCTInl/L6U9kUDtPYgU4IqA50IeQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3BSZN%2FbtsDhhCTInl%2FL6U9kUDtPYgU4IqA50IeQ1%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;435&quot; height=&quot;328&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;392&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;성별과 시간대에 따른 팁 Violin Plot 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림을 보면 BoxPlot에 비해서 데이터의 분포가 더욱 명확하게 그려지는 것을 확인할 수 있으며, 이상치를 명확하게 표현하는 Box Plot과 다르게 이상치에 대한 정보가 명확하게 표시되지 않는 것을 확인할 수 있다.&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;●Bar Plot&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;범주형 데이터의 평균 또는 기타 통계량을 막대그래프로 나타내어 데이터 간 비교를 용이하게 해주는 시각화 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bar Plot의 주요 특징으로 범주형 데이터에 대한 평균, 합계, 빈도 등의 통계량을 시각적으로 표현이 가능하고, 여러 범주를 한 번에 비교하기 용이하며, 각 범주의 차이를 쉽게 파악할 수 있어 데이터 시각화 중 가장 많이 사용되는 시각화 중 하나이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 BarPlot의 시각화 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1704800165731&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 시간대와 성별 별 total_bill의 Bar Plot
sns.barplot(x = 'time', y = 'total_bill', data = tip, hue = 'sex')&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;506&quot; data-origin-height=&quot;381&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oij5I/btsDiRjfceA/Kt9knKwljp7tVBfzWba4cK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oij5I/btsDiRjfceA/Kt9knKwljp7tVBfzWba4cK/img.png&quot; data-alt=&quot;시간대와 성별 별 total_bill의 barplot&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oij5I/btsDiRjfceA/Kt9knKwljp7tVBfzWba4cK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Foij5I%2FbtsDiRjfceA%2FKt9knKwljp7tVBfzWba4cK%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;386&quot; height=&quot;291&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;381&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;시간대와 성별 별 total_bill의 barplot&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그래프를 통하여 확인할 수 있는 것은, 시간대가 Lunch와 Dinner 중 total_bill이 Dinner가 더 높고, 남자와 여자 중 남자가 여자에 비해 total_bill이 높다는 것을 확인할 수 있다.&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;●DistPlot&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선 그래프로 변화 추이를 나타내기 위한 시각화 방법이며, matplotlib의 hist와 kdeplot을 통합한 그래프이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통하여 분포와 밀도를 BoxPlot보다 더욱 명확하게 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 분포와 밀도를 통하여 데이터가 정규분포를 따르는지 판단을 하는데 도움을 줄 수 있어, 자주 사용하는 시각화 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 DistPlot의 시각화 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1704800897650&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# tip 데이터 total_bill의 distplot 코드
sns.distplot(tip['total_bill'], bins = 20, kde = True)&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;520&quot; data-origin-height=&quot;391&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kX06v/btsDd4RVKKt/JioR8Dj8CHRZCjp8oyQb30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kX06v/btsDd4RVKKt/JioR8Dj8CHRZCjp8oyQb30/img.png&quot; data-alt=&quot;tip데이터의 total_bill의 distplot&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kX06v/btsDd4RVKKt/JioR8Dj8CHRZCjp8oyQb30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkX06v%2FbtsDd4RVKKt%2FJioR8Dj8CHRZCjp8oyQb30%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;423&quot; height=&quot;318&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;391&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;tip데이터의 total_bill의 distplot&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그래프를 통해 total_bill 데이터가 이러한 분포를 따른다는 것을 확인할 수 있다.&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;●ScatterPlot&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ScatterPlot은 두 변수 간의 관계를 시각화하기 위한 산점도를 그리는데 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;산점도를 통하여 데이터의 분포 및 경향성을 파악을 할 수 있으며, 특이값이나 이상치를 시각적으로 확인이 가능하고, 두 연속형 변수간의 상관 관계또한 시각적으로 파악을 할 수 있다. ScatterPlot 또한 자주 사용하는 시각화 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 ScatterPlot의 시각화 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1704805191195&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# x축에 total_bill, y축에 tip을 두고 hue를 smoker로 지정하여 산점도를 그림
sns.scatterplot(x = 'total_bill', y = 'tip', data = tip, hue = 'smoker')&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;553&quot; data-origin-height=&quot;426&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNudRw/btsDdDs5Pmt/EAF9AcheMoY55KEfhRph60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNudRw/btsDdDs5Pmt/EAF9AcheMoY55KEfhRph60/img.png&quot; data-alt=&quot;total_bill과 tip의 산점도&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNudRw/btsDdDs5Pmt/EAF9AcheMoY55KEfhRph60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNudRw%2FbtsDdDs5Pmt%2FEAF9AcheMoY55KEfhRph60%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;453&quot; height=&quot;349&quot; data-origin-width=&quot;553&quot; data-origin-height=&quot;426&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;total_bill과 tip의 산점도&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 ScatterPlot 산점도 그림을 통하여 total_bill과 tip에는 상관 관계가 존재하는 것으로 파악되며, 흡연 여부는 total_bill과 tip에 영향을 미치지 않는다는 것을 파악할 수 있다.&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;●CatPlot&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Catplot은 hue와 row 등을 동시에 사용해 3개 이상의 카테고리 값에 의한 분포 변화를 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Catplot에서 kind라는 매개변수가 있는데 이는 자신이 그리고 싶은 종류의 시각화를 적으면 그 그래프에 맞춰서 시각화를 시켜준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 Catplot의 시각화 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1704802355709&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#plt.rc('font', family='Malgun Gothic')  -&amp;gt; 한글 깨짐현상을 해결
# 팁을 기준으로 성별과 흡연여부, 시간대를 한꺼번에 검사를 하며, kind = 'violin'으로
# 그림을 violin plot으로 그려준다.
sns.catplot(x = 'tip', y = 'sex', hue = 'smoker', row = 'time', data = tip, kind = 'violin', split = True, height = 2, aspect = 4)
plt.title('성별, 흡연여부, 시간대에 따른 tip의 Catplot')
plt.show()&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;686&quot; data-origin-height=&quot;309&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rjV9S/btsC8Xy4GKN/0ydVLysR8qIofNatgDUMS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rjV9S/btsC8Xy4GKN/0ydVLysR8qIofNatgDUMS0/img.png&quot; data-alt=&quot;tip에 대한 성별, 흡연여부, 시간대에 따른 Catplot&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rjV9S/btsC8Xy4GKN/0ydVLysR8qIofNatgDUMS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrjV9S%2FbtsC8Xy4GKN%2F0ydVLysR8qIofNatgDUMS0%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;579&quot; height=&quot;261&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;309&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;tip에 대한 성별, 흡연여부, 시간대에 따른 Catplot&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 kind = 'violin'으로 하여 violin plot을 그려주었다. 또한 두개의 카테고리값이 아닌 3개 이상의 카테고리 값에 의한 시각화를 그려준다.&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;●LmPlot&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;lmplot은 열 간의 선형관계를 확인하기에 용이한 차트로써 outlier도 간접적으로 짐작해 볼 수 있다. 이 시각화 방법은 산점도를 그리고 산점도에 맞는 선형을 그려준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 lmplot의 시각화 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1704803151206&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# total_bill과 tip의 선형관계 확인
sns.lmplot(x = 'total_bill', y = 'tip', data = tip)&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;498&quot; data-origin-height=&quot;479&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfYmsP/btsDivHks0R/cfPekS5A3ssUgg5coTX1n1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfYmsP/btsDivHks0R/cfPekS5A3ssUgg5coTX1n1/img.png&quot; data-alt=&quot;total_bill과 tip의 lmplot 시각화&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfYmsP/btsDivHks0R/cfPekS5A3ssUgg5coTX1n1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfYmsP%2FbtsDivHks0R%2FcfPekS5A3ssUgg5coTX1n1%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;369&quot; height=&quot;355&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;479&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;total_bill과 tip의 lmplot 시각화&lt;/figcaption&gt;
&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;●JointPlot&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JointPlot은 ScatterPlot 산점도와 Histogram을 동시에 그려주는 시각화 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 JointPlot은 수치형 데이터만 표현이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 JointPlot의 시각화 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1704805493105&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# x축에 total_bill, y축에 tip을 넣어 jointplot 시각화를 수행
sns.jointplot(x = 'total_bill', y = 'tip', data = tip)&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;587&quot; data-origin-height=&quot;591&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqkbhR/btsDfnwLpb4/ejLboO6bS7emTrc6LBxapK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqkbhR/btsDfnwLpb4/ejLboO6bS7emTrc6LBxapK/img.png&quot; data-alt=&quot;total_bill과 tip의 jointplot 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqkbhR/btsDfnwLpb4/ejLboO6bS7emTrc6LBxapK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqkbhR%2FbtsDfnwLpb4%2FejLboO6bS7emTrc6LBxapK%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;464&quot; height=&quot;467&quot; data-origin-width=&quot;587&quot; data-origin-height=&quot;591&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;total_bill과 tip의 jointplot 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림을 확인해보면 기본적으로 ScatterPlot이 그려져 있으며, 빈 x축 위쪽에는 total_bill의 히스토그램, 빈 y축 오른쪽에는 tip의 히스토그램이 한꺼번에 그려져 있는 것을 확인할 수 있다. JointPlot을 사용함으로써 히스토그램과 산점도를 따로 그릴필요 없이 한꺼번에 그릴 수 있어 시각화를 효율적으로 할 수 있을 것이다.&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;●PairPlot&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;아래는 PairPlot의 시각화 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1704806266570&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 전체 데이터인 tip 에 대한 pairplot 코드
sns.pairplot(tip)&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;606&quot; data-origin-height=&quot;599&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/scYaB/btsC83TPWuG/JNzf3suub9sCkivCAHk60k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/scYaB/btsC83TPWuG/JNzf3suub9sCkivCAHk60k/img.png&quot; data-alt=&quot;전체 데이터(tip)의 pairplot 시각화&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/scYaB/btsC83TPWuG/JNzf3suub9sCkivCAHk60k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FscYaB%2FbtsC83TPWuG%2FJNzf3suub9sCkivCAHk60k%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;461&quot; height=&quot;456&quot; data-origin-width=&quot;606&quot; data-origin-height=&quot;599&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;전체 데이터(tip)의 pairplot 시각화&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림처럼 tip 데이터 내부에 존재하는 모든 수치형 변수 쌍 끼리의 ScatterPlot(산점도)를 그리고 대각선으로는 Histogram(히스토그램)을 그려준다. 모든 수치형 변수 쌍 끼리의 산점도와 히스토그램을 그려줘서 편하지만, 데이터의 열 중 수치형 변수의 열이 많아질수록 크기가 커지기 때문에 너무 많은 수치형 변수가 존재할 때 사용하면 보기 힘들다는 단점이 존재한다.&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;●HeatMap&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 데이터의 각 셀에 색상을 사용하여 값을 시각적으로 나타내는데 사용한다. 주로 행렬 형태의 데이터를 시각화할 때 유용하다. 이러한 히트맵으로는 주로 상관 관계를 많이 확인하는 편이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 HeatMap의 시각화 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1704877685336&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# tip 데이터 프레임의 데이터를 .corr()을 통해 얻은 상관 계수를 corr_tip에 저장
corr_tip = tip.corr()

# 상관 계수를 저장한 데이터를 넣고 시각화
sns.heatmap(corr_tip, annot = True)&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;518&quot; data-origin-height=&quot;425&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RHZGt/btsDkMh74pC/ju7kP9HNqHIUuXb7EVnGyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RHZGt/btsDkMh74pC/ju7kP9HNqHIUuXb7EVnGyk/img.png&quot; data-alt=&quot;tip데이터의 상관 계수 히트맵&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RHZGt/btsDkMh74pC/ju7kP9HNqHIUuXb7EVnGyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRHZGt%2FbtsDkMh74pC%2Fju7kP9HNqHIUuXb7EVnGyk%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;392&quot; height=&quot;322&quot; data-origin-width=&quot;518&quot; data-origin-height=&quot;425&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;tip데이터의 상관 계수 히트맵&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 시각화 결과를 확인하면 데이터 중 수치형 변수에 대한 상관관계 수치를 확인할 수 있다. 또한 더욱 명확한 시각화를 하기 위하여 annot이라는 수치까지 포함해주는 매개 변수를 사용하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 이외에도 사용할 색상 맵을 지정하는 cmap, 셀 간 경계의 두께와 색상을 지정하는 linewidths와 linecolor, 컬러바(색상막대)를 표시할지 여부를 지정하는 cbar, 각각 x축과 y축의 눈금 레이블을 표시할지 여부를 지정하는 xticklabels, yticklabels 등이 존재합니다. 위 다양한 매개변수를 활용하여 시각화를 더욱 보기 좋게 만드는 것도 다른사람이 보는 입장에서 매우 좋을 것이다.&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;이 이외에도 seaborn 패키지의 시각화는 더 존재할 것이지만, 이정도의 시각화 방법만 가지고 있으면 데이터의 분포, 추세, 특징을 찾아내는데에는 문제 없을 것이다.&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;이제부터 위 설명한 시각화 방법에 대한 주요 매개변수를 설명을 할 것이다.&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;●Seaborn 패키지의 주요 매개변수들&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- hue: 범주형 변수를 지정하여 데이터를 색상으로 구분&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- size: 점의 크기를 조절하는데 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- palette: hue에 사용될 색상 팔레트를 지정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- markers: 각 범주형 변수의 마커를 지정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- col, row: 데이터를 여러 서브플롯으로 나눌 때 사용되는 변수를 지정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- alpha: 각 점의 투명도를 지정 (0~1 사이)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- legend: 범례를 표시할지 여부 지정 -&amp;gt; 파생된 매개변수 legend_out: 범례를 서브플롯 밖으로 위치시킬지 여부 지정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- sharex, sharey: 서브플롯 간 x축 또는 y축을 공유할지 여부 지정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- colors, col_colors, row_colors: 데이터에 색을 지정, col_colors, row_colors는 col과 row의 변수 색 지정&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;이렇게 Seaborn 패키지의 시각화 방법과 주요 매개변수들에 대해서 살펴보았다. 이를 활용해서 데이터에 대한 인사이트를 얻는데 도움이 되었으면 좋겠다.&lt;/p&gt;</description>
      <category>Python 공부 - 잡다한 것들</category>
      <author>DataKwon</author>
      <guid isPermaLink="true">https://koy0911.tistory.com/9</guid>
      <comments>https://koy0911.tistory.com/9#entry9comment</comments>
      <pubDate>Wed, 10 Jan 2024 18:13:09 +0900</pubDate>
    </item>
    <item>
      <title>Python .txt 파일 다루기 - RadishSurvey.txt 데이터 다루기</title>
      <link>https://koy0911.tistory.com/8</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 DSAC 자격증 취득을 위한 공부를 하던 중 텍스트로만 이루어진 .txt 파일인 RadishSurvey.txt를 가지고 텍스트 데이터를 다루는 것을 할 것이다.&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;/p&gt;
&lt;pre id=&quot;code_1703660861229&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
import numpy as np

# with open으로 .txt 파일을 radish라는 이름으로 들고와준다.
with open('./data/radishsurvey.txt') as radish:
    for line in radish:
        print(line, end = '')&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;317&quot; data-origin-height=&quot;305&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/72IhY/btsCMyx4SrM/kCF8DghjP7kW7rHOCdlmiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/72IhY/btsCMyx4SrM/kCF8DghjP7kW7rHOCdlmiK/img.png&quot; data-alt=&quot;텍스트 파일 내용&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/72IhY/btsCMyx4SrM/kCF8DghjP7kW7rHOCdlmiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F72IhY%2FbtsCMyx4SrM%2FkCF8DghjP7kW7rHOCdlmiK%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;264&quot; height=&quot;254&quot; data-origin-width=&quot;317&quot; data-origin-height=&quot;305&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;텍스트 파일 내용&lt;/figcaption&gt;
&lt;/figure&gt;
&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 데이터를 조금 더 쉽게 파악해보도록 이름과 무로 분리해서 이름과 투표한 무를 나눠본다.&lt;/p&gt;
&lt;pre id=&quot;code_1703661289695&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 무 선호도 설문조사 텍스트 파일 열기
with open('./data/radishsurvey.txt') as radish:
# 분리기준을 - 로 설정해서 투표자 이름과 투표한 무 이름 구분
    for line in radish:
        line = line.strip()
        devide = line.split(' - ')
        # 투표자 이름을 name에 저장
        name = devide[0]
        # 투표한 무 이름을 radishvote에 저장
        radishvote = devide[1]

        print(f&quot;Name of person: {name}&quot;)
        print(f&quot;Name of Radish: {radishvote}&quot;)
        print('-'*10)&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;283&quot; data-origin-height=&quot;309&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHDXgT/btsCKR5YKx7/xYs7fICLgdy5rwQtx7Szx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHDXgT/btsCKR5YKx7/xYs7fICLgdy5rwQtx7Szx1/img.png&quot; data-alt=&quot;투표자와 투표를 한 무 이름&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHDXgT/btsCKR5YKx7/xYs7fICLgdy5rwQtx7Szx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHDXgT%2FbtsCKR5YKx7%2FxYs7fICLgdy5rwQtx7Szx1%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;258&quot; height=&quot;282&quot; data-origin-width=&quot;283&quot; data-origin-height=&quot;309&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;투표자와 투표를 한 무 이름&lt;/figcaption&gt;
&lt;/figure&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;이렇게 무를 투표를 하였는데 과연 설문조사를 한 사람은 어느 무를 선호를 하는지에 대해서 알아보고 싶어진다. 이를 알아보기 위해 각 투표된 무 별로 어느 무가 가장 많이 투표가 되었는지 확인을 해본다.&lt;/p&gt;
&lt;pre id=&quot;code_1703661869807&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# countdown 이라는 딕셔너리 생성
countdown = {}

with open('./data/radishsurvey.txt') as radish:
    for line in radish:
        line = line.strip()
        # vote_name 과 vote_radish를 - 기준으로 분리한 값을 넣어준다.
        vote_name, vote_radish = line.split(' - ')
        # 분리해서 얻은 vote_radish가 countdown이라는 딕셔너리 안에 존재한다면?
        if vote_radish in countdown:
        	# countdown 딕셔너리 안에 vote_radish에 1을 더해라
            countdown[vote_radish] += 1
        # 그것이 아니라면 countdown 딕셔너리 내부 vote_radish에 1을 넣어라
        else:
            countdown[vote_radish] = 1
print(countdown)&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;709&quot; data-origin-height=&quot;124&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIScS3/btsCKo3NhdT/dp9LHbtIQzUNGnI7VCp3vK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIScS3/btsCKo3NhdT/dp9LHbtIQzUNGnI7VCp3vK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIScS3/btsCKo3NhdT/dp9LHbtIQzUNGnI7VCp3vK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIScS3%2FbtsCKo3NhdT%2Fdp9LHbtIQzUNGnI7VCp3vK%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;709&quot; height=&quot;124&quot; data-origin-width=&quot;709&quot; data-origin-height=&quot;124&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드를 보면 - 기준으로 값을 분리해서 vote_name과 vote_radish로 투표자 이름과 투표한 무 이름을 뽑아내었고, 그 중 투표한 무 이름을 if문을 사용해 투표한 무 이름이 중복되는 기준으로 숫자 1을 더해 무에 대한 투표 수를 얻을 수 있다.&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;예를들면 April Cross라는 무는 67투표가 되어있는데 아래를 확인해보면 april cross와 April cross라는 대소문자만 다른 값에도 개별적으로 투표가 5개가 되어있기 때문에 이에 대해서 처리를 수행해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1703662391403&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;countdown = {}

with open('./data/radishsurvey.txt') as radish:
    for line in radish:
    	# 문자열에서 양 끝의 공백을 제거하고, 그 후에 첫 글자를 대문자로 만든 결과를 반환
        line = line.strip().capitalize()
        # - 를 기준으로 값을 분리해 vote_name과 vote_radish에 값을 넣어줌
        vote_name, vote_radish = line.split(' - ')
# 중간에 띄어쓰기 두번이 되어있었던 문제가 있어서 replace함수를 통해 띄어쓰기 두번된 것 한번으로 변환
        vote_radish = vote_radish.replace('  ', ' ')
        # vote_radish 양쪽 끝 공백 제거
        vote_radish = vote_radish.strip()
        if vote_radish in countdown:
            countdown[vote_radish] += 1
        else:
            countdown[vote_radish] = 1
print(countdown)&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;705&quot; data-origin-height=&quot;61&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qrKLX/btsCN8eQRwx/fBElajH4CE881KCeUo7wnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qrKLX/btsCN8eQRwx/fBElajH4CE881KCeUo7wnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qrKLX/btsCN8eQRwx/fBElajH4CE881KCeUo7wnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqrKLX%2FbtsCN8eQRwx%2FfBElajH4CE881KCeUo7wnk%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;705&quot; height=&quot;61&quot; data-origin-width=&quot;705&quot; data-origin-height=&quot;61&quot;/&gt;&lt;/span&gt;&lt;/figure&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;이제 투표자에 대해서 확인해봐야할 것이 존재한다. 먼저 투표자가 두번 투표한 경우가 존재할 수도 있을 것이다. 이러한 투표자를 찾아보도록 한다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1703663020674&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# countdown 딕셔너리 생성
countdown = {}
# 집합 생성
name_of_vote = set()

with open('./data/radishsurvey.txt') as radish:
    for line in radish:
        line = line.strip().capitalize()
        vote_name, vote_radish = line.split(' - ')
        
        vote_radish = vote_radish.replace('  ', ' ')
        vote_radish = vote_radish.strip()
        
        vote_name = vote_name.strip().capitalize()
        vote_name = vote_name.replace('  ', ' ')
        
        if vote_radish in countdown:
            countdown[vote_radish] += 1
        else:
            countdown[vote_radish] = 1
        
        if vote_name in name_of_vote:
            print(vote_name, 'is already voted!')
        else:
            name_of_vote.add(vote_name)&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;252&quot; data-origin-height=&quot;42&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5CuV2/btsCMpOHd7g/X4qJksVwwsD6zDQVyvmBUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5CuV2/btsCMpOHd7g/X4qJksVwwsD6zDQVyvmBUk/img.png&quot; data-alt=&quot;중복투표자 이름&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5CuV2/btsCMpOHd7g/X4qJksVwwsD6zDQVyvmBUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5CuV2%2FbtsCMpOHd7g%2FX4qJksVwwsD6zDQVyvmBUk%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;252&quot; height=&quot;42&quot; data-origin-width=&quot;252&quot; data-origin-height=&quot;42&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;중복투표자 이름&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 방식을 통해 중복 투표자를 확인을 해 본 결과 Phoebe barwell과 Procopio zito 라는 사람이 중복으로 투표를 한 것을 확인할 수 있었다. 이러한 중복 투표자가 존재한 것을 확인하였으니 투표에서 중복 투표자의 표를 제외하여 투표된 무의 횟수를 다시 확인을 해본다.&lt;/p&gt;
&lt;pre id=&quot;code_1703663386362&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;countdown = {}
name_of_vote = set()

with open('./data/radishsurvey.txt') as radish:
    for line in radish:
        line = line.strip().capitalize()
        vote_name, vote_radish = line.split(' - ')
        
        vote_radish = vote_radish.replace('  ', ' ')
        vote_radish = vote_radish.strip()
        
        vote_name = vote_name.strip().capitalize()
        vote_name = vote_name.replace('  ', ' ')
        
        # 중복 투표자는 표를 무시하고 다음 루프로 이동
        if vote_name in name_of_vote:
            print(vote_name, 'is already voted!')
            continue
        
        if vote_radish in countdown:
            countdown[vote_radish] += 1
        else:
            countdown[vote_radish] = 1
        
        name_of_vote.add(vote_name)

print('\nCount of Radish', end = '\n')
for vote_radish in sorted(countdown):
    print(vote_radish, ': ', str(countdown[vote_radish]))&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;249&quot; data-origin-height=&quot;245&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDkfEf/btsCBLTlhAP/oOJ2UNDBfmmT4E1Dx4ilSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDkfEf/btsCBLTlhAP/oOJ2UNDBfmmT4E1Dx4ilSk/img.png&quot; data-alt=&quot;중복 투표자 제거한 투표 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDkfEf/btsCBLTlhAP/oOJ2UNDBfmmT4E1Dx4ilSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDkfEf%2FbtsCBLTlhAP%2FoOJ2UNDBfmmT4E1Dx4ilSk%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;249&quot; height=&quot;245&quot; data-origin-width=&quot;249&quot; data-origin-height=&quot;245&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;중복 투표자 제거한 투표 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중복 투표자의 표를 제거를 해보니 white icicle과 plum purple이 중복으로 투표되었단 것을 알 수 있다. 이제 사람들이 투표한 무에 대한 횟수는 완료되었다. 이제 설문에서 각 무에 대한 비율을 파이차트를 통해서 확인해본다.&lt;/p&gt;
&lt;pre id=&quot;code_1703663786239&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
import matplotlib.pyplot as plt

# countdown 딕셔너리를 데이터프레임 형태로 변환하여 countdown_df에 저장
countdown_df = pd.DataFrame(list(countdown.items()), columns=['Radish', 'Count'])
# 잘 적용되었는지 확인
countdown_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;190&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/be92fo/btsCCAc90hS/BOrhhMv92NBcwCDkyjJc4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/be92fo/btsCCAc90hS/BOrhhMv92NBcwCDkyjJc4K/img.png&quot; data-alt=&quot;딕셔너리를 데이터프레임형태로 변환&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/be92fo/btsCCAc90hS/BOrhhMv92NBcwCDkyjJc4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbe92fo%2FbtsCCAc90hS%2FBOrhhMv92NBcwCDkyjJc4K%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;190&quot; height=&quot;278&quot; data-origin-width=&quot;190&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;딕셔너리를 데이터프레임형태로 변환&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무사히 countdown 딕셔너리의 값을 countdown_df라는 데이터 프레임 형태로 변환을 시켜 주었다. 이제 데이터 프레임을 가지고 파이차트를 그려 선호하는 무의 비율을 확인해볼 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1703663916438&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 파이차트
plt.figure(figsize=(8, 8))
plt.pie(countdown_df['Count'], labels=countdown_df['Radish'], autopct='%1.1f%%', startangle=90, colors=plt.cm.Paired.colors)
plt.title('Radish Voting Distribution')
plt.show()&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;669&quot; data-origin-height=&quot;578&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yhyaH/btsCF7IkHn3/6XKek2vBQKjKcHvR9wCRD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yhyaH/btsCF7IkHn3/6XKek2vBQKjKcHvR9wCRD0/img.png&quot; data-alt=&quot;설문조사한 선호하는 무에 대한 비율&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yhyaH/btsCF7IkHn3/6XKek2vBQKjKcHvR9wCRD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyhyaH%2FbtsCF7IkHn3%2F6XKek2vBQKjKcHvR9wCRD0%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;669&quot; height=&quot;578&quot; data-origin-width=&quot;669&quot; data-origin-height=&quot;578&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;설문조사한 선호하는 무에 대한 비율&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 파이차트를 통해 확인해본 결과 champion이 가장 선호하는 무이며 그 다음으로 april cross, bunny tail, french breakfast 라는 무가 선호되는 것을 확인할 수 있다.&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;/p&gt;
&lt;pre id=&quot;code_1703735501585&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;countdown = {}
name_of_vote = set()

with open('./data/radishsurvey.txt') as radish:
    for line in radish:
        line = line.strip().capitalize()
        vote_name, vote_radish = line.split(' - ')
        
        vote_radish = vote_radish.replace('  ', ' ')
        vote_radish = vote_radish.strip()
        
        vote_name = vote_name.strip().capitalize()
        vote_name = vote_name.replace('  ', ' ')
        
        if vote_radish in countdown:
            countdown[vote_radish].append(vote_name)
        else:
            countdown[vote_radish] = [vote_name]

for radishname, votersname in countdown.items():
    name_of_vote = set()
    
    # 투표자 이름을 name_of_vote의 집합에 넣어주면서, 중복 투표한 사람이면 제거해준다.
    for voter in votersname:
        if voter in name_of_vote:
            votersname.remove(voter)
        else:
            name_of_vote.add(voter)
            
# countdown딕셔너리에 저장된 투표 결과를 정렬하여 출력
for radishname, votersname in sorted(countdown.items()):
    print(&quot;###{} : {}&quot;.format(radishname, ', '.join(votersname)), end='.\n\n')

# 출력된 결과 txt파일로 저장
with open('sorting_radishsurvey.txt', 'w') as output_file:
    for radish, votersname in sorted(countdown.items()):
        output_file.write(f&quot;###{radish.capitalize()} : {', '.join(votersname)}.\n&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;703&quot; data-origin-height=&quot;313&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chO3w1/btsCMoijqDc/jjJvRrK5a813TldpB42TP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chO3w1/btsCMoijqDc/jjJvRrK5a813TldpB42TP0/img.png&quot; data-alt=&quot;설문조사한 무 별 투표자 이름&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chO3w1/btsCMoijqDc/jjJvRrK5a813TldpB42TP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchO3w1%2FbtsCMoijqDc%2FjjJvRrK5a813TldpB42TP0%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;703&quot; height=&quot;313&quot; data-origin-width=&quot;703&quot; data-origin-height=&quot;313&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;설문조사한 무 별 투표자 이름&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 무 별로 투표한 사람의 이름이 출력되도록 만들었으며, 이렇게 출력한 값을 sorting_radishsurvey.txt파일로 만들어 저장을 수행을 했다.&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;/p&gt;</description>
      <category>Python 공부 - 잡다한 것들</category>
      <author>DataKwon</author>
      <guid isPermaLink="true">https://koy0911.tistory.com/8</guid>
      <comments>https://koy0911.tistory.com/8#entry8comment</comments>
      <pubDate>Thu, 28 Dec 2023 12:57:44 +0900</pubDate>
    </item>
    <item>
      <title>Daicon 경진대회 - 학습플랫폼 이용자 구독 갱신 예측 모델링(2)</title>
      <link>https://koy0911.tistory.com/7</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이전까지 머신러닝 모델에 대한 학습 및 검정을 수행하고, 과대 과소적합이 모델에 존재하는지를 확인하는 방법 중 하나인 학습곡선을 이용해 모델 점수가 가장 높은 RandomForestClassifier에 대해 학습곡선을 그려본 결과 과대적합이 있다는 것을 확인할 수 있었다. 다른 머신러닝 모델의 학습곡선은 어떤지에 대해서 확인을 해보도록 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1703400899549&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;plt.figure(figsize=(15, 10))
plt.suptitle(&quot;Learning Curves&quot;, fontsize=16)

#첫번째 DTC
plt.subplot(2, 2, 1)
plt.title(&quot;Decision Tree Classifier&quot;)
plt.xlabel(&quot;Training examples&quot;)
plt.ylabel(&quot;Score&quot;)
plt.grid()
plt.fill_between(train_sizes, train_scores_mean - train_scores_std,
                 train_scores_mean + train_scores_std, alpha=0.1, color=&quot;r&quot;)
plt.fill_between(train_sizes, test_scores_mean - test_scores_std,
                 test_scores_mean + test_scores_std, alpha=0.1, color=&quot;g&quot;)
plt.plot(train_sizes, train_scores_mean, 'o-', color=&quot;r&quot;, label=&quot;Training score&quot;)
plt.plot(train_sizes, test_scores_mean, 'o-', color=&quot;g&quot;, label=&quot;Cross-validation score&quot;)
plt.legend(loc=&quot;best&quot;)

#두번째 SVC
plt.subplot(2, 2, 2)
plt.title(&quot;SVC&quot;)
plt.xlabel(&quot;Training examples&quot;)
plt.ylabel(&quot;Score&quot;)
plt.grid()
plt.fill_between(train_sizes1, train_scores_mean1 - train_scores_std1,
                 train_scores_mean1 + train_scores_std1, alpha=0.1, color=&quot;r&quot;)
plt.fill_between(train_sizes1, test_scores_mean1 - test_scores_std1,
                 test_scores_mean1 + test_scores_std1, alpha=0.1, color=&quot;g&quot;)
plt.plot(train_sizes1, train_scores_mean1, 'o-', color=&quot;r&quot;, label=&quot;Training score&quot;)
plt.plot(train_sizes1, test_scores_mean1, 'o-', color=&quot;g&quot;, label=&quot;Cross-validation score&quot;)
plt.legend(loc=&quot;best&quot;)

# 세번째 KNC
plt.subplot(2, 2, 3)
plt.title(&quot;KNeighbor Classifier&quot;)
plt.xlabel(&quot;Training examples&quot;)
plt.ylabel(&quot;Score&quot;)
plt.grid()
plt.fill_between(train_sizes2, train_scores_mean2 - train_scores_std2,
                 train_scores_mean2 + train_scores_std2, alpha=0.1, color=&quot;r&quot;)
plt.fill_between(train_sizes2, test_scores_mean2 - test_scores_std2,
                 test_scores_mean2 + test_scores_std2, alpha=0.1, color=&quot;g&quot;)
plt.plot(train_sizes2, train_scores_mean2, 'o-', color=&quot;r&quot;, label=&quot;Training score&quot;)
plt.plot(train_sizes2, test_scores_mean2, 'o-', color=&quot;g&quot;, label=&quot;Cross-validation score&quot;)
plt.legend(loc=&quot;best&quot;)

# 네번째 LR
plt.subplot(2, 2, 4)
plt.title(&quot;Logistic Regressor&quot;)
plt.xlabel(&quot;Training examples&quot;)
plt.ylabel(&quot;Score&quot;)
plt.grid()
plt.fill_between(train_sizes3, train_scores_mean3 - train_scores_std3,
                 train_scores_mean3 + train_scores_std3, alpha=0.1, color=&quot;r&quot;)
plt.fill_between(train_sizes3, test_scores_mean3 - test_scores_std3,
                 test_scores_mean3 + test_scores_std3, alpha=0.1, color=&quot;g&quot;)
plt.plot(train_sizes3, train_scores_mean3, 'o-', color=&quot;r&quot;, label=&quot;Training score&quot;)
plt.plot(train_sizes3, test_scores_mean3, 'o-', color=&quot;g&quot;, label=&quot;Cross-validation score&quot;)
plt.legend(loc=&quot;best&quot;)

plt.tight_layout()
plt.subplots_adjust(top=0.9)

# 그래프 출력
plt.show()&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;687&quot; data-origin-height=&quot;458&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ev8TB6/btsCyLFjz5k/HQGKibtzZMcJVY0P4g5C2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ev8TB6/btsCyLFjz5k/HQGKibtzZMcJVY0P4g5C2K/img.png&quot; data-alt=&quot;랜덤포레스트 제외한 나머지 모델 학습곡선&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ev8TB6/btsCyLFjz5k/HQGKibtzZMcJVY0P4g5C2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fev8TB6%2FbtsCyLFjz5k%2FHQGKibtzZMcJVY0P4g5C2K%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;687&quot; height=&quot;458&quot; data-origin-width=&quot;687&quot; data-origin-height=&quot;458&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;랜덤포레스트 제외한 나머지 모델 학습곡선&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지 학습모델 곡선을 확인해 본 결과 Logistic Regressor와 SVC는 Training Score가 처음부터 좋지 않으며, 점진적으로 하락하는 경향이 존재하기 때문에 모델 자체의 성능이 좋지 않은 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음으로는 Decision Tree Classifier인데 이 모델 또한 Training Score 점수가 1점으로 유지되는 확실한 과대적합 형태의 문제가 발생하고 있다. 이는 RandomForest Classifier에서도 발생한 문제였지만 Cross Validation Score는 RandomForestClassifier보다 약간 좋지 않아 DecisionTreeClassifier보단 RandomForestClassifier를 사용하는 것이 좋다고 생각된다. 마지막으로 KNeighborsClassifier는 Training Score의 점수가 0.75에서 0.85 사이에서 움직이는 괜찮은 점수를 가지고 있으며 Cross Validation Score또한 0.65에 근접하는 모델이기에 좋은 성능을 가지고 있을 것으로 판단되지만, 아직까지 Training Score와 Cross Validation Score의 점수가 큰 차이가 존재하기에 과대적합을 가지고 있는 것으로 확인할 수 있다.&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;먼저 RandomForestClassifier에서 과대적합이 발생했기 때문에 RandomForestClassifier의 하이퍼파라미터를 조정을 하여 모델의 최적값을 찾는 방식으로 과대적합을 없앨 수 있도록 할 것이다. 우리가 사용 할 하이퍼파라미터들은&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #374151; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;n_estimators:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #374151; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;의사결정나무의 개수를 지정합니다. 많은 트리를 사용하면 모델이 더 강력해지지만, 계산 비용이 증가하게 됩니다. 기본값은 100입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #374151; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;criterion:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #374151; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;노드의 분할 기준을 지정합니다. &quot;gini&quot; 또는 &quot;entropy&quot; 중에서 선택할 수 있습니다. 기본값은 &quot;gini&quot;입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #374151; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;max_depth:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #374151; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;각 의사결정나무의 최대 깊이를 제한합니다. 더 깊은 트리는 더 복잡한 모델을 생성할 수 있지만, 계산 비용이 증가합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #374151; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;min_samples_split:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #374151; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;노드를 분할하기 위한 최소한의 샘플 수를 지정합니다. 이 수보다 작으면 더 이상 분할하지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #374151; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;min_samples_leaf:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #374151; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;리프 노드가 가져야 하는 최소한의 샘플 수를 지정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 사용을 할 것이며, 먼저 최적의 하이퍼파라미터를 찾기 위해, 하이퍼파라미터 튜닝 방법 중 하나인 GridSearchCV방식을 사용을 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1703402057322&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# GridSearchCV
from sklearn.model_selection import GridSearchCV

# 찾을 하이퍼파라미터 수치 지정
rfc_param = {
    'n_estimators' : [100, 200, 300, 400],
    'max_depth' : [10, 15, 20],
    'min_samples_split' : [2, 5, 10],
    'min_samples_leaf' : [4, 8]
}

# 최적의 하이퍼파라미터 찾기
grid_search = GridSearchCV(estimator = rfc, param_grid=rfc_param, cv=5, scoring='accuracy')
grid_search.fit(x_train, y_train)

# 최적의 하이퍼파라미터 계수 확인
grid_search.best_params_&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;GridSearchCV를 사용해 랜덤포레스트 방법의 하이퍼파라미터 중 n_estimators, max_depth, min_samples_split, criterion, min_samples_leaf의 여러개의 계수를 지정하여 최적의 하이퍼파라미터 수치를 구한다. 수행되는데 오래 걸릴 것이기 때문에 기다려줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 하이퍼파라미터 중 최적의 계수를 확인해보니, n_estimators는 400, max_depth는 20, min_samples_leaf는 4, min_samples_split은 2로 나왔으며, n_estimators와 max_depth를 다시 고치며 최적의 하이퍼파라미터를 계속 검사한다.&lt;/p&gt;
&lt;pre id=&quot;code_1703505531455&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;rfc_param = {
    'n_estimators' : [400, 450, 500, 550],
    'max_depth' : [20, 25, 30, 35],
    'min_samples_split' : [2],
    'min_samples_leaf' : [4]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한번더 이 조건으로 해본 결과 최적의 하이퍼파리미터 계수는 max_depth는 30, n_estimators는 500이 나오게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이러한 하이퍼파라미터를 가지고 모델을 다시 만들어준다.&lt;/p&gt;
&lt;pre id=&quot;code_1703505927073&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 랜덤포레스트 모델 생성
parameter_rfc = RandomForestClassifier(n_estimators = 500, max_depth = 30, min_samples_leaf=4, min_samples_split=2, random_state = 42)
parameter_rfc.fit(x_train, y_train)

# 모델을 통한 예측값 생성
y_pred_rfc_param = parameter_rfc.predict(x_test)

# f1_score과 accuracy_score 검사
f1_rfc_param = f1_score(y_test, y_pred_rfc_param, average='macro')
accuracy_rfc_param = accuracy_score(y_test, y_pred_rfc_param)
# score점수 표시
print(f&quot;RandomForestClassifier -- f1_score: {f1_rfc_param}, accuracy_score: {accuracy_rfc_param} \n&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;656&quot; data-origin-height=&quot;38&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmLaPh/btsCzJ1DAn7/hjBj3yoJeJd73CSOKckKA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmLaPh/btsCzJ1DAn7/hjBj3yoJeJd73CSOKckKA1/img.png&quot; data-alt=&quot;하이퍼파라미터 튜닝한 RandomForestClassifier 점수&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmLaPh/btsCzJ1DAn7/hjBj3yoJeJd73CSOKckKA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdmLaPh%2FbtsCzJ1DAn7%2FhjBj3yoJeJd73CSOKckKA1%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;656&quot; height=&quot;38&quot; data-origin-width=&quot;656&quot; data-origin-height=&quot;38&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;하이퍼파라미터 튜닝한 RandomForestClassifier 점수&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 기본모델에 비해 0.07정도 좋아진 것을 확인할 수 있다. 그리고 모델을 복잡하게 만든 만 큼 과대적합이 해소가 되었는지 학습곡선을 통해 확인을 해본다.&lt;/p&gt;
&lt;pre id=&quot;code_1703506237347&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 하이퍼 파라미터 튜닝을 수행 한 RandomForestClassifier의 학습곡선
train_sizes_rfc, train_scores_rfc, test_scores_rfc = learning_curve(
    parameter_rfc, x_resampled, y_resampled, cv = 5, train_sizes=np.linspace(0.1, 1.0, 10))
    
train_scores_mean_rfc = np.mean(train_scores_rfc, axis=1)
train_scores_std_rfc = np.std(train_scores_rfc, axis=1)
test_scores_mean_rfc = np.mean(test_scores_rfc, axis=1)
test_scores_std_rfc = np.std(test_scores_rfc, axis=1)

plt.figure(figsize=(10, 6))
plt.title(&quot;Learning Curve&quot;)
plt.xlabel(&quot;Training examples&quot;)
plt.ylabel(&quot;Score&quot;)
plt.grid()

plt.fill_between(train_sizes_rfc, train_scores_mean_rfc - train_scores_std_rfc,
                 train_scores_mean_rfc + train_scores_std_rfc, alpha=0.1, color=&quot;r&quot;)
plt.fill_between(train_sizes_rfc, test_scores_mean_rfc - test_scores_std_rfc,
                 test_scores_mean_rfc + test_scores_std_rfc, alpha=0.1, color=&quot;g&quot;)
plt.plot(train_sizes_rfc, train_scores_mean_rfc, 'o-', color=&quot;r&quot;, label=&quot;Training score&quot;)
plt.plot(train_sizes_rfc, test_scores_mean_rfc, 'o-', color=&quot;g&quot;, label=&quot;Cross-validation score&quot;)

plt.legend(loc=&quot;best&quot;)
plt.show()&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;695&quot; data-origin-height=&quot;440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/22V6M/btsCG1NHpKQ/HMWlulexeko3qsjdSUb19k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/22V6M/btsCG1NHpKQ/HMWlulexeko3qsjdSUb19k/img.png&quot; data-alt=&quot;하이퍼파라미터 튜닝을 수행한 RandomForestClassifier 학습곡선&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/22V6M/btsCG1NHpKQ/HMWlulexeko3qsjdSUb19k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F22V6M%2FbtsCG1NHpKQ%2FHMWlulexeko3qsjdSUb19k%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;695&quot; height=&quot;440&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;440&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;하이퍼파라미터 튜닝을 수행한 RandomForestClassifier 학습곡선&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프를 보니 모델은 Training 데이터에 대해서 과대적합이 약간 해소가 되었지만 여전히 과대적합이 되어 있다는 것을 확인할 수 있었다. 모델의 복잡성을 줄여주는 방식을 추가 수행을 하여 과대적합을 없애줘야할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델의 복잡성을 줄여주는 방법으로는 주요 Feature 선택, 새로운 모델 선택, 규제 적용 등이 존재하는데, 그 중 Feature 선택을 한번 해보도록 할 것이다. 먼저 RandomForestClassifier에서 모델이 중요하게 생각한 변수에 대해서 출력해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1703509705708&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 변수 중요도 출력 -&amp;gt; 모델 학습을 했던 x_train의 columns 이름을 index로 사용
feature_importances = pd.Series(parameter_rfc.feature_importances_, index = x_train.columns)
print(feature_importances)&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;351&quot; data-origin-height=&quot;329&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nydVh/btsCAMw2UAV/lEdxhII3K4HwPY8ZdBUAa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nydVh/btsCAMw2UAV/lEdxhII3K4HwPY8ZdBUAa0/img.png&quot; data-alt=&quot;변수 중요도&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nydVh/btsCAMw2UAV/lEdxhII3K4HwPY8ZdBUAa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnydVh%2FbtsCAMw2UAV%2FlEdxhII3K4HwPY8ZdBUAa0%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;319&quot; height=&quot;299&quot; data-origin-width=&quot;351&quot; data-origin-height=&quot;329&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;변수 중요도&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수 중요도는 이렇게 나왔다. 위 변수 중 payment_pattern은 더미변수이므로 그대로 두고, 나머지 변수의 중요도가 낮은 것을 찾아보니 상대적으로 subscription_type과 preferred_difficulty_level, community_engagement_level이 낮게 나왔다. 이를 가지고만 판단하기 힘들 것으로 보여 상관계수 히트맵을 그려 독립변수끼리의 상관성이 존재하는지 확인을 해보고 상관성을 가지는 변수 중 변수 중요도가 낮은 것을 지워줘 다시 학습을 수행을 해 볼 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1703510071424&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# SMOTE 적용시킨 데이터에 대해 상관계수 계산
corr_data = x_resampled.corr()

# 데이터 프레임화(만약 corr_data가 데이터 프레임 형태가 아니라면)
corr_data = pd.DataFrame(corr_data)

#상관계수 히트맵 시각화
plt.figure(figsize = (10, 10))
sns.heatmap(corr_data, annot=True, annot_kws = {'size' : 6})
plt.show()&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;695&quot; data-origin-height=&quot;729&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqaOGB/btsCEIt8QU3/7JZ75eRh3okJXncR1LDh2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqaOGB/btsCEIt8QU3/7JZ75eRh3okJXncR1LDh2K/img.png&quot; data-alt=&quot;상관계수 히트맵&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqaOGB/btsCEIt8QU3/7JZ75eRh3okJXncR1LDh2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqaOGB%2FbtsCEIt8QU3%2F7JZ75eRh3okJXncR1LDh2K%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;626&quot; height=&quot;657&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;729&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;상관계수 히트맵&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;히트맵 결과 subscription_type과 total_completed_courses가 0.41정도의 상관관계를 가지고 있고, subscription_type과 community_engagement_level과 0.44정도의 상관관계를 가지고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이러한 상관관계 이외에 다른 데이터가 다중공선성을 가지는지에 대해서 확인해보기 위해 VIF(&lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;Variance Inflation Factor: 분산 팽창 요인)을 계산해본다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1703510530591&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# VIF 모듈
from statsmodels.stats.outliers_influence import variance_inflation_factor

# VIF 계산
def calculate_vif(data_frame):
    vif_data = pd.DataFrame()
    vif_data[&quot;Variable&quot;] = data_frame.columns
    vif_data[&quot;VIF&quot;] = [variance_inflation_factor(data_frame.values, i) for i in range(data_frame.shape[1])]
    return vif_data

# x_resampled 데이터의 VIF 계산
vif_result = calculate_vif(x_resampled)
# 출력
print(vif_result)&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;349&quot; data-origin-height=&quot;338&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Gy0HH/btsCywhuK9N/pwG9M21k1HRxNS1zCSI0k1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Gy0HH/btsCywhuK9N/pwG9M21k1HRxNS1zCSI0k1/img.png&quot; data-alt=&quot;변수에 대한 VIF 값&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Gy0HH/btsCywhuK9N/pwG9M21k1HRxNS1zCSI0k1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGy0HH%2FbtsCywhuK9N%2FpwG9M21k1HRxNS1zCSI0k1%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;349&quot; height=&quot;338&quot; data-origin-width=&quot;349&quot; data-origin-height=&quot;338&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;변수에 대한 VIF 값&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VIF 값을 확인해보니 다른 변수들은 문제가 없지만 community_engagement_level에는 VIF가 약5.72로 다중공선성이 존재할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;community_engagement_level은 랜덤포레스트의 변수 중요도가 0.032로 낮은 편이며, 상관관계에서도 subscription_type과 상관관계가 존재하므로 삭제를 해주는 것이 좋을 것 같다. 그리고 subscription_type과 total_completed_courses간의 상관 관계또한 존재하는데 그 중 subscription_type의 변수 중요도는 0.013으로 변수 중요도가 약 0.082인 total_completed_courses보다 매우 낮기 때문에 subscription_type 변수를 삭제한 후 모델을 만들어보도록 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1703511794078&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 데이터를 복사하여 사용할 것
x_resampled_copy = x_resampled.copy()

# 복사한 데이터에서 subscription_type과 community_engagement_level 삭제
x_resampled_copy.drop(['subscription_type', 'community_engagement_level'], axis = 1, inplace = True)

# train, test 데이터로 분리
x_train1, x_test1, y_train1, y_test1 = train_test_split(x_resampled_copy, y_resampled, test_size = 0.2, random_state = 42)

# 모델 선정(하이퍼파라미터 선정)
parameter_rfc = RandomForestClassifier(n_estimators = 500, max_depth = 30, min_samples_leaf=4, min_samples_split=2, random_state = 42)
# 모델 생성
parameter_rfc.fit(x_train1, y_train1)

# 모델로 x_test값 예측
y_pred_rfc_param = parameter_rfc.predict(x_test1)

# 점수 계산
f1_rfc_param = f1_score(y_test1, y_pred_rfc_param, average='macro')
accuracy_rfc_param = accuracy_score(y_test1, y_pred_rfc_param)

print(f&quot;RandomForestClassifier -- f1_score: {f1_rfc_param}, accuracy_score: {accuracy_rfc_param} \n&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;658&quot; data-origin-height=&quot;35&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y9bDa/btsCxHcHFZu/5eo0tR9BwImrWnribKhxpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y9bDa/btsCxHcHFZu/5eo0tR9BwImrWnribKhxpk/img.png&quot; data-alt=&quot;변수 제거 후 랜덤포레스트 점수&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y9bDa/btsCxHcHFZu/5eo0tR9BwImrWnribKhxpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy9bDa%2FbtsCxHcHFZu%2F5eo0tR9BwImrWnribKhxpk%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;658&quot; height=&quot;35&quot; data-origin-width=&quot;658&quot; data-origin-height=&quot;35&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;변수 제거 후 랜덤포레스트 점수&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수를 제거 한 후 모델을 학습하고 점수를 계산하니 점수에 대한 큰 변화는 존재하지 않았다. 이제 모델이 과대적합이 되어 있는지 확인해보기 위해 학습곡선을 그려서 확인해본 후 하이퍼파라미터 튜닝을 다시 수행하여 마무리 한 후 머신러닝 모델링에 대해서 마치고, TensorFlow Dense를 이용한 예측모델 생성을 해보도록 하겠다.&lt;/p&gt;
&lt;pre id=&quot;code_1703512434129&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 변수 제거한 x_resampled_copy를 이용해 학습곡선을 그려본다.
from sklearn.model_selection import learning_curve
train_sizes_rfc, train_scores_rfc, test_scores_rfc = learning_curve(
    parameter_rfc, x_resampled_copy, y_resampled, cv = 5, train_sizes=np.linspace(0.1, 1.0, 10))
    
train_scores_mean_rfc = np.mean(train_scores_rfc, axis=1)
train_scores_std_rfc = np.std(train_scores_rfc, axis=1)
test_scores_mean_rfc = np.mean(test_scores_rfc, axis=1)
test_scores_std_rfc = np.std(test_scores_rfc, axis=1)

plt.figure(figsize=(10, 6))
plt.title(&quot;Learning Curve&quot;)
plt.xlabel(&quot;Training examples&quot;)
plt.ylabel(&quot;Score&quot;)
plt.grid()

plt.fill_between(train_sizes_rfc, train_scores_mean_rfc - train_scores_std_rfc,
                 train_scores_mean_rfc + train_scores_std_rfc, alpha=0.1, color=&quot;r&quot;)
plt.fill_between(train_sizes_rfc, test_scores_mean_rfc - test_scores_std_rfc,
                 test_scores_mean_rfc + test_scores_std_rfc, alpha=0.1, color=&quot;g&quot;)
plt.plot(train_sizes_rfc, train_scores_mean_rfc, 'o-', color=&quot;r&quot;, label=&quot;Training score&quot;)
plt.plot(train_sizes_rfc, test_scores_mean_rfc, 'o-', color=&quot;g&quot;, label=&quot;Cross-validation score&quot;)

plt.legend(loc=&quot;best&quot;)
plt.show()&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;703&quot; data-origin-height=&quot;444&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ea2BRK/btsCzGcRvkh/Rjkey7GUiXTVrViK4nXen1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ea2BRK/btsCzGcRvkh/Rjkey7GUiXTVrViK4nXen1/img.png&quot; data-alt=&quot;변수 제거한 랜덤포레스트 모델 학습곡선&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ea2BRK/btsCzGcRvkh/Rjkey7GUiXTVrViK4nXen1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fea2BRK%2FbtsCzGcRvkh%2FRjkey7GUiXTVrViK4nXen1%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;587&quot; height=&quot;371&quot; data-origin-width=&quot;703&quot; data-origin-height=&quot;444&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;변수 제거한 랜덤포레스트 모델 학습곡선&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학습곡선에 큰 변화가 존재하지 않은 것 같다. 이제 하이퍼파라미터 튜닝을 통해서 과대적합을 최대한 조절해보도록 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1703512721613&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# GridSearchCV - 하이퍼파라미터 탐색하는 모듈
from sklearn.model_selection import GridSearchCV
# 검사할 하이퍼파라미터 값
rfc_grid_param = {
    'n_estimators' : [100, 200],
    'max_depth' : [5, 10],
    'min_samples_split' : [None, 2, 5],
    'min_samples_leaf' : [None, 2, 5]
}

# 최적의 하이퍼파라미터 탐색
grid_search = GridSearchCV(estimator = parameter_rfc, param_grid=rfc_grid_param, cv=5, scoring='accuracy')
grid_search.fit(x_train1, y_train1)

# 최선의 하이퍼파라미터 값 출력
grid_search.best_params_&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하이퍼 파라미터 값을 계속 탐색해본 결과 max_depth는 30, min_samples_leaf와 split은 2, n_estimators는 250으로 나왔기 때문에 이에 맞춰서 모델을 생성하도록 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1703513803683&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 랜덤포레스트 새로운 모델 생성
param_rfc_v2 = RandomForestClassifier(n_estimators = 250, max_depth = 30, min_samples_leaf = 2, min_samples_split = 2, random_state = 42)
param_rfc_v2.fit(x_train1, y_train1)

# 점수 계산 및 표시
y_pred_v1 = param_rfc_v2.predict(x_test1)

# 점수 계산
f1_rfc_param_v1 = f1_score(y_test1, y_pred_v1, average='macro')
accuracy_rfc_param_v1 = accuracy_score(y_test1, y_pred_v1)

print(f&quot;RandomForestClassifier -- f1_score: {f1_rfc_param_v1}, accuracy_score: {accuracy_rfc_param_v1} \n&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;652&quot; data-origin-height=&quot;33&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0Gpvd/btsCzucAsHd/3QN9OTMpO2RnxhkTzqaCf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0Gpvd/btsCzucAsHd/3QN9OTMpO2RnxhkTzqaCf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0Gpvd/btsCzucAsHd/3QN9OTMpO2RnxhkTzqaCf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0Gpvd%2FbtsCzucAsHd%2F3QN9OTMpO2RnxhkTzqaCf1%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;652&quot; height=&quot;33&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;33&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RandomForestClassifier의 모델 점수가 상승한 것을 확인할 수 있다. 이제 이 모델이 과대적합인지 학습곡선을 한번 더 그려 확인해본 후 머신러닝 모델링은 마무리하도록 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1703514255260&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;train_sizes_rfc2, train_scores_rfc2, test_scores_rfc2 = learning_curve(
    param_rfc_v2, x_resampled_copy, y_resampled, cv = 5, train_sizes=np.linspace(0.1, 1.0, 10))

train_scores_mean_rfc2 = np.mean(train_scores_rfc2, axis=1)
train_scores_std_rfc2 = np.std(train_scores_rfc2, axis=1)
test_scores_mean_rfc2 = np.mean(test_scores_rfc2, axis=1)
test_scores_std_rfc2 = np.std(test_scores_rfc2, axis=1)

plt.figure(figsize=(10, 6))
plt.title(&quot;Learning Curve&quot;)
plt.xlabel(&quot;Training examples&quot;)
plt.ylabel(&quot;Score&quot;)
plt.grid()

plt.fill_between(train_sizes_rfc2, train_scores_mean_rfc2 - train_scores_std_rfc2,
                 train_scores_mean_rfc2 + train_scores_std_rfc2, alpha=0.1, color=&quot;r&quot;)
plt.fill_between(train_sizes_rfc2, test_scores_mean_rfc2 - test_scores_std_rfc2,
                 test_scores_mean_rfc2 + test_scores_std_rfc2, alpha=0.1, color=&quot;g&quot;)
plt.plot(train_sizes_rfc2, train_scores_mean_rfc2, 'o-', color=&quot;r&quot;, label=&quot;Training score&quot;)
plt.plot(train_sizes_rfc2, test_scores_mean_rfc2, 'o-', color=&quot;g&quot;, label=&quot;Cross-validation score&quot;)

plt.legend(loc=&quot;best&quot;)
plt.show()&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;696&quot; data-origin-height=&quot;449&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ohAwI/btsCywPkVec/6w4VY1Zw4eySFZyJ0nKFek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ohAwI/btsCywPkVec/6w4VY1Zw4eySFZyJ0nKFek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ohAwI/btsCywPkVec/6w4VY1Zw4eySFZyJ0nKFek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FohAwI%2FbtsCywPkVec%2F6w4VY1Zw4eySFZyJ0nKFek%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;601&quot; height=&quot;388&quot; data-origin-width=&quot;696&quot; data-origin-height=&quot;449&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학습곡선을 확인해본 결과 아직까지도 과대적합이 되어있다는 것을 알 수 있다. 무조건적으로 GridSearchCV를 수행하지 않고 모델의 복잡성을 감소시키는 방향으로 모델을 짜서 다시 확인해보면서 고쳐나가야할 것이다.&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;이제부턴 DeepLearning 모델인 TensorFlow Dense 방법을 사용하여 모델을 제작하도록 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1703515298658&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 필요 모듈들 불러오기
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import f1_score
from tensorflow.keras.regularizers import l2
from keras.layers import Dropout

# 모델의 Layer 층 값 입력
model = Sequential()
model.add(Dense(512, input_dim=x_train1.shape[1], activation='relu'))
#model.add(Dropout(0.1))

model.add(Dense(256, activation='relu'))
#model.add(Dropout(0.1))

model.add(Dense(128, activation='relu'))
#model.add(Dropout(0.1))

model.add(Dense(64, activation='relu'))
#model.add(Dropout(0.1))

model.add(Dense(32, activation='relu'))
#model.add(Dropout(0.1))

model.add(Dense(16, activation='relu'))
#model.add(Dropout(0.1))

#model.add(Dense(16, activation='relu'))
#model.add(Dropout(0.1))

model.add(Dense(1, activation='sigmoid'))

# 최적화 함수 Adam &amp;amp; 학습률 0.001로 지정
from tensorflow.keras.optimizers import Adam
optimizer = Adam(learning_rate=0.001)

# 과대적합 방지를 위한 Early Stopping -&amp;gt; val_loss 기준 30번 비슷한 수치면 정지
from tensorflow.keras.callbacks import EarlyStopping
early_stopping = EarlyStopping(monitor='val_loss', patience=30, restore_best_weights=True)
model.compile(loss = 'binary_crossentropy', optimizer = optimizer, metrics = ['accuracy'])

# 모델 학습 시작
history = model.fit(x_train1, y_train1, epochs=150, batch_size = 16, validation_split=0.2, callbacks=[early_stopping])

# 모델에 대한 loss와 val_loss 시각화
import matplotlib.pyplot as plt
plt.plot(history.history['loss'], 'b-', label = 'loss')
plt.plot(history.history['val_loss'], 'r-', label = 'val_loss')
plt.xlabel('Epoch')
plt.legend()
plt.show()&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;499&quot; data-origin-height=&quot;392&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kxrNU/btsCy6v6pfk/991Yp1Jr330shYxakNrLp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kxrNU/btsCy6v6pfk/991Yp1Jr330shYxakNrLp1/img.png&quot; data-alt=&quot;loss와 val_loss 추이&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kxrNU/btsCy6v6pfk/991Yp1Jr330shYxakNrLp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkxrNU%2FbtsCy6v6pfk%2F991Yp1Jr330shYxakNrLp1%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;499&quot; height=&quot;392&quot; data-origin-width=&quot;499&quot; data-origin-height=&quot;392&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;loss와 val_loss 추이&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1개의 입력층과 1개의 출력층 사이에 4개의 은닉층으로 이루어진 모델이며, 활성화 함수로는 relu함수와 sigmoid함수를 사용, 최적화 함수로는 Adam을 사용하고 학습률도 0.001로 지정한 후 val_loss 기준으로 30번 점수가 유지되면 멈추는 Early Stopping을 지정했다. 모델에 대한 Epoch별 loss와 val_loss또한 시각화를 하여 과대적합인지, 과소적합인지 확인을 해보니 loss는 줄어들고 val_loss가 증가를 하면 과대적합일 가능성이 매우 높다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과대적합인 것을 알았으니, 과대적합을 해결하기 위해 모델의 복잡도를 낮춰야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방법으로는, DropOut 방법과 모델의 복잡도 감소 방법, 더 많은 데이터 추가하는 방법 등이 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 그 중 Dropout 방법과 모델 복잡도 감소 방법을 함께 사용을 하여서 과대적합을 제거를 시도할 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1703516594115&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 모델 + DropOut방법 + 은닉층 수 감소
model = Sequential()
model.add(Dense(128, input_dim=x_train1.shape[1], activation='relu'))
model.add(Dropout(0.3))

model.add(Dense(64, activation='relu'))
model.add(Dropout(0.3))

model.add(Dense(32, activation='relu'))
#model.add(Dropout(0.3))

model.add(Dense(16, activation='relu'))
#model.add(Dropout(0.3))

#model.add(Dense(32, activation='relu'))
#model.add(Dropout(0.1))

#model.add(Dense(16, activation='relu'))
#model.add(Dropout(0.1))

#model.add(Dense(16, activation='elu'))
#model.add(Dropout(0.1))

model.add(Dense(1, activation='sigmoid'))

from tensorflow.keras.optimizers import Adam
optimizer = Adam(learning_rate=0.001)
model.compile(loss = 'binary_crossentropy', optimizer = optimizer, metrics = ['accuracy'])

from tensorflow.keras.callbacks import EarlyStopping

early_stopping = EarlyStopping(monitor='val_loss', patience=15, restore_best_weights=True)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드를 통해 모델의 은닉층을 줄여 모델 복잡도를 감소시키면서 DropOut 방법과 함께 수치를 0.3으로 지정해 삭제를 수행하여 모델의 복잡도를 줄여주었다. 또한 Early Stopping을 30번이 아닌 15번 비슷한 값이 유지가 되면 정지되게 바꾸어서 모델 학습을 수행을 해보았다.&lt;/p&gt;
&lt;pre id=&quot;code_1703516695584&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 모델 학습
history = model.fit(x_train1, y_train1, epochs=150, batch_size = 8, validation_split=0.2, callbacks=[early_stopping])

# 시각화
import matplotlib.pyplot as plt
plt.plot(history.history['loss'], 'b-', label = 'loss')
plt.plot(history.history['val_loss'], 'r-', label = 'val_loss')
plt.xlabel('Epoch')
plt.legend()
plt.show()&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;514&quot; data-origin-height=&quot;398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CGm8Q/btsCAjhqOcT/WZRDkrKRXXGzSKfvBK3gZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CGm8Q/btsCAjhqOcT/WZRDkrKRXXGzSKfvBK3gZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CGm8Q/btsCAjhqOcT/WZRDkrKRXXGzSKfvBK3gZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCGm8Q%2FbtsCAjhqOcT%2FWZRDkrKRXXGzSKfvBK3gZK%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;514&quot; height=&quot;398&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;398&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과로는 이런 loss값들이 나오게 되었다. 전과 같은 완전한 과대적합은 아닌 것으로 보인다. 더 정확하게 보기 위해 학습곡선을 이용해서 확인을 해본다.&lt;/p&gt;
&lt;pre id=&quot;code_1703517556686&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 학습곡선 그래프 
plt.plot(history.history['accuracy'], 'b-', label='Training Accuracy')
plt.plot(history.history['val_accuracy'], 'r-', label='Validation Accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()&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;531&quot; data-origin-height=&quot;386&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8JBoI/btsCxE1nzVq/2cSmaDcEL3X3ISNOMFvodk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8JBoI/btsCxE1nzVq/2cSmaDcEL3X3ISNOMFvodk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8JBoI/btsCxE1nzVq/2cSmaDcEL3X3ISNOMFvodk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8JBoI%2FbtsCxE1nzVq%2F2cSmaDcEL3X3ISNOMFvodk%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;531&quot; height=&quot;386&quot; data-origin-width=&quot;531&quot; data-origin-height=&quot;386&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학습곡선을 보니 학습은 얼추 잘 된 것 같지만, Validation Accuracy가 0.6에서 그 이상의 성능을 끌어올리지 못하지만 Training Accuracy는 점진적으로 점점 증가하고 있는 것을 보면서 아직까지 과대적합의 현상이 남아있는 것을 확인 할 수 있다. 만약 과대적합을 해결해서 모델이 좋게 나온 것을 확인했다면, 예측값을 만들어준다.&lt;/p&gt;
&lt;pre id=&quot;code_1703517872535&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 예측값 구하기(예측값이 0, 1로 나오는 것이 아닌 정수값으로 나옴)
y_pred_dense = model.predict(x_test1)

# 0.5값을 기준으로 이상이면 1, 이하이면 0의 값으로 만들어서 넣어줌
y_pred_dense = (y_pred &amp;gt; 0.5).astype('int')

#모델에 대한 f1_score와 m1_macro 점수
macro_f1_dense = f1_score(y_test, y_pred_dense, average='macro')
accuracy_dense = accuracy_score(y_test, y_pred_dense)
print(accuracy_dense, '\n')
print(macro_f1_dense)&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;260&quot; data-origin-height=&quot;58&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxbwx9/btsCyJHTcKV/ZZpb4NLJwJzUt6zshwwiN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxbwx9/btsCyJHTcKV/ZZpb4NLJwJzUt6zshwwiN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxbwx9/btsCyJHTcKV/ZZpb4NLJwJzUt6zshwwiN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbxbwx9%2FbtsCyJHTcKV%2FZZpb4NLJwJzUt6zshwwiN0%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;260&quot; height=&quot;58&quot; data-origin-width=&quot;260&quot; data-origin-height=&quot;58&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Accuracy_score하고 Macro f1 score의 점수가 평범한 편이다. &lt;s&gt;(아직 과대적합이 존재하는 모델이어서 그런것 같다.)&lt;/s&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;모델을 가지고 실제 test_data의 예측값을 구한 후 결과 값에 넣어주도록 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1703518379533&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 위의 x_reshaped 데이터에서 상관관계와 다중공선성으로 삭제한 데이터를 test에서도 삭제
test_data.drop(['subscription_type', 'community_engagement_level'], axis = 1, inplace = True)

# test_data에 대해서 예측값을 구함
predictions_dense = model.predict(test_data)

# 구한 예측값에서 0.5를 기준으로 0과 1로 만들어줌
predictions_dense = (predictions_dense &amp;gt; 0.5).astype('int')

# 바꾼 예측값을 result_data의 target 열 값에 넣어줌
result_data['target'] = predictions_dense

# 잘 들어갔는지 확인
result_data&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;151&quot; data-origin-height=&quot;288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDrLVB/btsCJklYiyn/aq58W6jMWkDzQ1M4t7z540/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDrLVB/btsCJklYiyn/aq58W6jMWkDzQ1M4t7z540/img.png&quot; data-alt=&quot;TensorFlow Dense의 예측결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDrLVB/btsCJklYiyn/aq58W6jMWkDzQ1M4t7z540/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDrLVB%2FbtsCJklYiyn%2Faq58W6jMWkDzQ1M4t7z540%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;137&quot; height=&quot;261&quot; data-origin-width=&quot;151&quot; data-origin-height=&quot;288&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;TensorFlow Dense의 예측결과&lt;/figcaption&gt;
&lt;/figure&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;pre id=&quot;code_1703518466880&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# result_data를 경로에 저장한다.
result_data.to_csv('./dataset/resultdata/dense_f_eng_result_v1.csv', index=False)&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;이렇게 모든 모델링을 해보게 되었다. 위의 모델링 방법 말고도 다른 좋은 모델링 방법이 존재할 것이고, 이에 대해서도 한번 다뤄보고 싶었으며, 과대적합과 과소적합에 대한 문제를 해결하기가 어려운 것 같았던 것 같다.&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;이 대회에서의 성적으로 답을 제출한 사람 기준 380명 중 79등으로(상위 21퍼) 경진대회를 마감하게 되었다.&lt;/p&gt;</description>
      <category>데이터 모델링</category>
      <author>DataKwon</author>
      <guid isPermaLink="true">https://koy0911.tistory.com/7</guid>
      <comments>https://koy0911.tistory.com/7#entry7comment</comments>
      <pubDate>Tue, 26 Dec 2023 00:40:46 +0900</pubDate>
    </item>
    <item>
      <title>Daicon 경진대회 - 학습플랫폼 이용자 구독 갱신 예측 모델링</title>
      <link>https://koy0911.tistory.com/6</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Daicon 경진대회 - 학습플랫폼 이용자 구독 갱신 예측에 대한 모델링을 수행해보았다.&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;EDA 및 분석을 실시한 결과는&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. train_data와 test_data에서의 분포는 preferred_difficulty_level을 제외하고 차이가 없다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. average_time_per_learning_session은 오른쪽으로 꼬리가 긴 양수 왜도 형태를 띈다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3. train_data의 boxplot결과에서는 이상치가 존재하는 것 처럼 보였지만 train_data에서 test_data의&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;최대 최소값에 벗어나는 값이 존재하는지 확인해보니 없기 때문에 이상치가 따로 존재하지 않는 것 같다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4. 커뮤니티 참여도가 낮을수록 총 학습 코스 수가 적다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;5. 커뮤니티 참여도가 낮을수록&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;각 학습 세션에 소요된 평균 시간&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;도 낮다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;6. 선호 난이도가 높을수록 완료한 총 코스 수가 낮다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;7. 선호 난이도가 높을수록 각 학습 세션에 소요된 평균 시간이 낮다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;8. 완료한 총 코스 수는 구독 유형이 Premium인 사람이 Basic인 사람보다 높다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;9. 각 학습 세션에 소요된 평균 시간은 Premium인 사람이 Basic인 사람보다 높다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;10. target변수에 대해서 데이터 불균형이 존재한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이러한 결론이 내려졌기 떄문에 모델링을 위한 데이터 전처리는 이에 맞게 실행을 한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;먼저 기초적인 모듈을 들고와준 후 데이터를 들고와준다.&lt;/p&gt;
&lt;pre id=&quot;code_1703224877103&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
import numpy as np
import warnings
warnings.filterwarnings('ignore')

train_data = pd.read_csv('./dataset/subscription/train.csv')
test_data = pd.read_csv('./dataset/subscription/test.csv')
result_data = pd.read_csv('./dataset/subscription/sample_submission.csv')&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;먼저 데이터에서 모델링을 할 때 필요없는 데이터인 user_id를 지워준 후 변수 정보를 찾아본다.&lt;/p&gt;
&lt;pre id=&quot;code_1703225008481&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;train_data = train_data.drop('user_id', axis = 1)
test_data = test_data.drop('user_id', axis = 1)

print(train_data.info(), '\n')
print(test_data.info())&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;462&quot; data-origin-height=&quot;681&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvfiZW/btsCso47hb6/kkaVi8iKKuSN1hkymIoqYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvfiZW/btsCso47hb6/kkaVi8iKKuSN1hkymIoqYk/img.png&quot; data-alt=&quot;train, test 데이터 열 정보&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvfiZW/btsCso47hb6/kkaVi8iKKuSN1hkymIoqYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvfiZW%2FbtsCso47hb6%2FkkaVi8iKKuSN1hkymIoqYk%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;347&quot; height=&quot;511&quot; data-origin-width=&quot;462&quot; data-origin-height=&quot;681&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;train, test 데이터 열 정보&lt;/figcaption&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;그 다음 EDA결과 중 하나인 &quot;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;10. target변수에 대해서 데이터 불균형이 존재한다.&quot; 가 있는데, 데이터 불균형이 존재하면&amp;nbsp; 모델 학습을 할 때 정확도의 한계, 과적합 문제, 평가지표의 왜곡이 존재할 수 도 있기 때문에 데이터가 얼마나 불균형한지 확인을 해본다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1703225990795&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 데이터를 target 기준으로 groupby로 묶어준 후 count해준다.
df1 = train_data.groupby('target').count()

# 파이차트 시각화
plt.pie(data = df1, x = 'subscription_duration',labels=df1.index, autopct = lambda x : '{:.1f}%'.format(x))
plt.legend()
plt.show()&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;341&quot; data-origin-height=&quot;329&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EM0RG/btsCsiDZ6eU/MiowQkU98AONHwXIeqOrz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EM0RG/btsCsiDZ6eU/MiowQkU98AONHwXIeqOrz1/img.png&quot; data-alt=&quot;target변수의 비율&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EM0RG/btsCsiDZ6eU/MiowQkU98AONHwXIeqOrz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEM0RG%2FbtsCsiDZ6eU%2FMiowQkU98AONHwXIeqOrz1%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;341&quot; height=&quot;329&quot; data-origin-width=&quot;341&quot; data-origin-height=&quot;329&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;target변수의 비율&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;종속변수인 target이 62대 38로 약간의 데이터 불균형이 존재하는 것으로 보인다.&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;데이터 불균형이 약간 존재하는 것을 확인을 했기 때문에, 종속변수인 target을 따로 값을 빼준 후 train_data에서 target을 삭제해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1703225207607&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# train_data의 target 변수를 target_y로 새로 만들어줌
target_y = train_data['target']
# target데이터 삭제
train_data.drop('target', axis=1, inplace = True)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 모델 학습을 위해서 종속변수인 target까지 처리를 해주었다.&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;또한 데이터의 총 개수를 확인해보니 10000개의 행인 비교적 적은 양의 데이터로 이루어 진 것 또한 알수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 데이터의 양을 늘려주면서 종속변수의 데이터 불균형도 처리해줄 수 있도록 오버샘플링 방법 중 하나인 SMOTE 방식을 사용하여 데이터의 양도 늘려주며 데이터 불균형 문제도 해소할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SMOTE방식에는 단점도 존재하는데, &lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;소수 클래스의 데이터가 과하게 늘어나 &lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;소수 클래스에 과도하게 적합되고, 실제 데이터와의 일반화 성능이 저하될 가능성&lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;이 있으며&lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;, &lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;이상치에 민감한 모델에서는 이러한 이상치가 부정적인 영향을 끼칠 수 있으며, &lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;SMOTE는 주로 이진 분류 문제에 사용되기 때문에 다중 클래스 문제에 대한 처리가 상대적으로 어려울 수 있는 문제점들이 있지만, EDA를 해봤을 때 문제가 되는 이상치가 존재하지 않았으며, 데이터 불균형이 크지 않기 때문에 소수 클래스에 과도하게 적합될 가능성이 적어보였으며, 우리가 풀어야하는 문제는 이진분류 문제이기 때문에 이러한 SMOTE 방식을 사용하기로 정하였다.&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;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;이러한 SMOTE 방식을 적용하기 전 데이터에 대한 전처리를 미리 수행하는 것이 좋다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;먼저 데이터 전처리 하기 전 payment_pattern과 preferred_difficulty_level은 수치형으로 나오지만 데이터의 내용은 범주형과 같기 때문에 이 둘을 object 타입으로 변환을 시켜준다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1703227043021&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# train_data에서 community_engagement_level과 payment_pattern을 object 범주형으로 변환
train_data['community_engagement_level'] = train_data['community_engagement_level'].astype('object')
train_data['payment_pattern'] = train_data['payment_pattern'].astype('object')

# test_data또한 변환
test_data['community_engagement_level'] = test_data['community_engagement_level'].astype('object')
test_data['payment_pattern'] = test_data['payment_pattern'].astype('object')

# 잘 변환되었는지 확인
print(train_data.info(), '\n')
print(test_data.info())&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;470&quot; data-origin-height=&quot;665&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ddskpb/btsCshkRyT1/ecziJuNIDFW9bDfYQwsAC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ddskpb/btsCshkRyT1/ecziJuNIDFW9bDfYQwsAC0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ddskpb/btsCshkRyT1/ecziJuNIDFW9bDfYQwsAC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fddskpb%2FbtsCshkRyT1%2FecziJuNIDFW9bDfYQwsAC0%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;312&quot; height=&quot;441&quot; data-origin-width=&quot;470&quot; data-origin-height=&quot;665&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;community_engagement_level과 payment_pattern이 변환이 잘 된 것을 확인할 수 있다.&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;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;그 후 수치형 변수와 범주형 변수를 따로 변환시키기 위해 열을 뽑아내주도록 한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1703227229717&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 범주형 변수 열 리스트
col_cat = train_data.select_dtypes(include='object').columns.tolist()
# 수치형 변수 열 리스트
col_num = train_data.select_dtypes(exclude='object').columns.tolist()

print(col_cat, '\n')
print(col_num)&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;709&quot; data-origin-height=&quot;102&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cW6PEi/btsCxC1Czyu/rM4Nln4uFukBSPygWcXOtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cW6PEi/btsCxC1Czyu/rM4Nln4uFukBSPygWcXOtK/img.png&quot; data-alt=&quot;범주형 변수와 수치형 변수의 열&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cW6PEi/btsCxC1Czyu/rM4Nln4uFukBSPygWcXOtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcW6PEi%2FbtsCxC1Czyu%2FrM4Nln4uFukBSPygWcXOtK%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;709&quot; height=&quot;102&quot; data-origin-width=&quot;709&quot; data-origin-height=&quot;102&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;범주형 변수와 수치형 변수의 열&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;데이터 타입이 범주형인지 수치형인지에 따라 잘 분리되어서 리스트에 입력 잘 되었는지 확인해보니 잘 된것을 알 수 있다.&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;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;이제 EDA결과 중 &quot; &lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;2. average_time_per_learning_session은 오른쪽으로 꼬리가 긴 양수 왜도 형태를 띈다.&quot;에 대해서 데이터를 로그변환을 시켜 데이터 분포의 대칭성을 향상시켜준다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1703227488696&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# average_time_per_learning_session을 로그변환 시켜 분포의 대칭성 향상
train_data['average_time_per_learning_session'] = np.log1p(train_data['average_time_per_learning_session'])
test_data['average_time_per_learning_session'] = np.log1p(test_data['average_time_per_learning_session'])&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;이제 수치형 데이터에 대해서 스케일링을 수행을 할 것이다. 스케일링에 대한 방법론의 대표적인 방법으로, Min-Max Scaler, Standard Scaler, Robust Scaler가 존재하는데, 그 중 우리는 Standard Scaler를 사용을 할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 각 스케일링 방법에 대한 장단점이 존재하기 때문이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #374151; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;RobustScaler:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장점: 이상치에 강건함.&lt;/li&gt;
&lt;li&gt;단점: 이상치가 없는 경우에는 다른 스케일러들과 성능이 비슷할 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;StandardScaler:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장점: 대부분의 경우에 효과적.&lt;/li&gt;
&lt;li&gt;단점: 이상치에 민감할 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MinMaxScaler:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장점: 데이터를 [0, 1] 범위로 정규화하여 동일한 스케일을 가지게 함.&lt;/li&gt;
&lt;li&gt;단점: 이상치에 민감할 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 장단점을 확인하며 Standard Scaler가 이상치에 영향이 적다면 대부분의 경우 효과적이기 때문에 사용하기로 한 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Standard Scaler를 train_data와 test_data에 적용을 시켜본다.&lt;/p&gt;
&lt;pre id=&quot;code_1703228304556&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.preprocessing import StandardScaler
ss = StandardScaler() # Standard Scaler를 ss로 지정

# 수치형 데이터의 열을 저장한 col_num을 이용해 모든 수치형데이터의 열에 Standard Scaler수행
train_data[col_num] = ss.fit_transform(train_data[col_num])
test_data[col_num] = ss.fit_transform(test_data[col_num])

# 잘 적용되었는지 확인
train_data.head()&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;707&quot; data-origin-height=&quot;141&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dv7BtM/btsCs905owh/soRZbFXj27zzeHQmkhoG7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dv7BtM/btsCs905owh/soRZbFXj27zzeHQmkhoG7K/img.png&quot; data-alt=&quot;train_data의 수치형 데이터들이 StandardScaler 적용 되었는지 확인&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dv7BtM/btsCs905owh/soRZbFXj27zzeHQmkhoG7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdv7BtM%2FbtsCs905owh%2FsoRZbFXj27zzeHQmkhoG7K%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;141&quot; data-origin-width=&quot;707&quot; data-origin-height=&quot;141&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;train_data의 수치형 데이터들이 StandardScaler 적용 되었는지 확인&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 Standard Scaler가 잘 적용된 것을 확인을 할 수 있다.&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;범주형 변수의 인코딩 방법 또한 여러가지 방법이 존재한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #374151; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;원핫 인코딩 (One-Hot Encoding):&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;장점:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;범주 간의 순서나 계층을 나타내지 않으므로 명목형 변수에 적합합니다.&lt;/li&gt;
&lt;li&gt;모델에 범주형 정보를 제공하여 성능을 향상시킬 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단점:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;범주의 개수가 많은 경우, 특성의 차원이 증가하여 희소성이 증가하고 모델의 학습과 예측에 부담이 될 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;라벨 인코딩 (Label Encoding):&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;장점:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;범주 간의 순서가 있는 경우에 활용 가능합니다.&lt;/li&gt;
&lt;li&gt;정수로 인코딩되어 연산이 빠르고 저장 공간을 절약합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단점:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;순서가 없는 명목형 변수에는 적합하지 않습니다.&lt;/li&gt;
&lt;li&gt;모델이 인코딩된 순서에 영향을 받을 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 외에도 많은 방법이 있지만 대표적으론 위 방법들이 존재한다. 원-핫 인코딩 방법은 순서나 계층이 없는 데이터에 대한 변환을 할 때 좋고, 라벨 인코딩은 순서가 있는 데이터에 대해서 수행을 하면 좋다는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 특성을 따라 순서가 존재하는 community_engagement_level, preferred_difficulty_level, subscription_type은 라벨 인코딩, 순서가 없는 payment_pattern은 원-핫 인코딩인 더미변수화를 시켜줄 것이다.&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;먼저 payment_pattern을 더미변수화를 시켜준다.&lt;/p&gt;
&lt;pre id=&quot;code_1703229262919&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;train_data = pd.get_dummies(train_data, columns = ['payment_pattern'])
test_data = pd.get_dummies(test_data, columns = ['payment_pattern'])
train_data.head()&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;704&quot; data-origin-height=&quot;132&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byHA2y/btsCt7oj1FM/rYXKvpsKjkMH1WRtjKMB20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byHA2y/btsCt7oj1FM/rYXKvpsKjkMH1WRtjKMB20/img.png&quot; data-alt=&quot;payment_pattern 더미변수화 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byHA2y/btsCt7oj1FM/rYXKvpsKjkMH1WRtjKMB20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyHA2y%2FbtsCt7oj1FM%2FrYXKvpsKjkMH1WRtjKMB20%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;704&quot; height=&quot;132&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;132&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;payment_pattern 더미변수화 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;payment_pattern에 대한 더미변수화가 잘 수행된 것 같다.&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;라벨 인코딩을 이제 수행해보도록 하는데, 라벨 인코딩은 1차원 배열에서만 작동하기 때문에 각각 하나씩 적용을 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1703230060837&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.preprocessing import LabelEncoder
le = LabelEncoder

train_data['community_engagement_level'] = le.fit_transform(train_data['community_engagement_level'])
test_data['community_engagement_level'] = le.fit_transform(test_data['community_engagement_level'])

train_data['preferred_difficulty_level'] = le.fit_transform(train_data['preferred_difficulty_level'])
test_data['preferred_difficulty_level'] = le.fit_transform(test_data['preferred_difficulty_level'])

train_data['subscription_type'] = le.fit_transform(train_data['subscription_type'])
test_data['subscription_type'] = le.fit_transform(test_data['subscription_type'])

train_data.head()&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;435&quot; data-origin-height=&quot;138&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/021dp/btsCuMqTisd/y6Xy6xkJAwv6G6JbPGR1S0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/021dp/btsCuMqTisd/y6Xy6xkJAwv6G6JbPGR1S0/img.png&quot; data-alt=&quot;라벨 인코딩 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/021dp/btsCuMqTisd/y6Xy6xkJAwv6G6JbPGR1S0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F021dp%2FbtsCuMqTisd%2Fy6Xy6xkJAwv6G6JbPGR1S0%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;435&quot; height=&quot;138&quot; data-origin-width=&quot;435&quot; data-origin-height=&quot;138&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;라벨 인코딩 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;community_engagement_level, preferred_difficulty_level, subscription_type의 라벨 인코딩이 잘 적용되었다.&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;이렇게 변수들에 대한 스케일링 및 인코딩이 완료되었기 때문에 이제 SMOTE를 수행을 할 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1703226777828&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from imblearn.over_sampling import SMOTE #SMOTE 모듈
smote = SMOTE(sampling_strategy='auto') #auto로 지정해 데이터의 양을 1대1로 만들어 늘려준다.

# SMOTE 적용
x_resampled, y_resampled = smote.fit_resample(train_data, target_y)

# SMOTE 적용한 데이터 확인
x_resampled&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;707&quot; data-origin-height=&quot;303&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qJhQA/btsCwL54FEy/gramEsPnSNdxRbSkaOGNI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qJhQA/btsCwL54FEy/gramEsPnSNdxRbSkaOGNI0/img.png&quot; data-alt=&quot;SMOTE 적용 데이터&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qJhQA/btsCwL54FEy/gramEsPnSNdxRbSkaOGNI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqJhQA%2FbtsCwL54FEy%2FgramEsPnSNdxRbSkaOGNI0%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;569&quot; height=&quot;244&quot; data-origin-width=&quot;707&quot; data-origin-height=&quot;303&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SMOTE 적용 데이터&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SMOTE 적용으로 10000개의 데이터가 12398개의 데이터로 증가한 것을 확인할 수 있다.&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 전에 데이터를 train, validation, test로 분리를 할 것이지만 validation은 데이터의 양이 12398개로 많지 않기 떄문에 분리하지 않고 train, test로만 데이터를 8대 2로 분리할 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1703230609640&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(x_resampled, y_resampled, test_size = 0.2, random_state = 42)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;random_state 시드를 42로 지정하고 test_sizefmf 0.2로 지정하여 train, test를 8대 2로 나눴으며, 데이터는 SMOTE를 수행한 x_resampled과 y_resampled를 사용하였다.&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;/p&gt;
&lt;pre id=&quot;code_1703230670097&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression

dtc = DecisionTreeClassifier(random_state = 42) # 의사결정나무 분류기
rfc = RandomForestClassifier(random_state = 42) # 랜덤포레스트 분류기 
svc = SVC(random_state = 42)  #서포트벡터 머신 분류기
knc = KNeighborsClassifier(n_neighbors = 3) # 이웃수 3 / 최근접이웃 분류기
lr = LogisticRegression()  #로지스틱 회귀

dtc.fit(x_train, y_train)  # 의사결정나무 모델생성

rfc.fit(x_train, y_train)  # 랜덤포레스트 모델생성

svc.fit(x_train, y_train)  # 서포트벡터 머신 모델생성

knc.fit(x_train, y_train)  # 최근접 이웃 모델생성

lr.fit(x_train, y_train)  # 로지스틱 회귀 모델생성&lt;/code&gt;&lt;/pre&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;이제 모델에 대한 성능 점수를 계산을 한다. 위 경진대회에선 macro_f1의 점수를 기준으로 등수를 매겼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇지만 나는 macro_f1과 함께 accuracy_score까지 함께 확인해보도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1703231895724&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.metrics import f1_score # f1_score 점수
from sklearn.metrics import accuracy_score # accuracy_score 점수

# 분리한 x_test로 모델별 예측값 생성
y_pred_dtc = dtc.predict(x_test)
y_pred_rfc = rfc.predict(x_test)
y_pred_svc = svc.predict(x_test)
y_pred_knc = knc.predict(x_test)
y_pred_lr = lr.predict(x_test)

# macro_f1 score 점수 계산
f1_score_dtc = f1_score(y_test, y_pred_dtc, average='macro')
f1_score_rfc = f1_score(y_test, y_pred_rfc, average='macro')
f1_score_svc = f1_score(y_test, y_pred_svc, average='macro')
f1_score_knc = f1_score(y_test, y_pred_knc, average='macro')
f1_score_lr = f1_score(y_test, y_pred_lr, average='macro')

# accuracy_score 점수 계산
accuracy_dtc = accuracy_score(y_test, y_pred_dtc)
accuracy_rfc = accuracy_score(y_test, y_pred_rfc)
accuracy_svc = accuracy_score(y_test, y_pred_svc)
accuracy_knc = accuracy_score(y_test, y_pred_knc)
accuracy_lr = accuracy_score(y_test, y_pred_lr)

# 점수 결과
print(f&quot;DecisionTreeClassifier -- f1_score: {f1_score_dtc}, accuracy_score: {accuracy_dtc} \n&quot;)
print(f&quot;RandomForestClassifier -- f1_score: {f1_score_rfc}, accuracy_score: {accuracy_rfc} \n&quot;)
print(f&quot;SVC -- f1_score: {f1_score_svc}, accuracy_score: {accuracy_svc} \n&quot;)
print(f&quot;KNeighborsClassifier -- f1_score: {f1_score_knc}, accuracy_score: {accuracy_knc} \n&quot;)
print(f&quot;LogisticRegressor -- f1_score: {f1_score_lr}, accuracy_score: {accuracy_lr}&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;647&quot; data-origin-height=&quot;154&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3vk9Z/btsCyvH0DCf/Nvjrv4a6goLzACMiohjK60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3vk9Z/btsCyvH0DCf/Nvjrv4a6goLzACMiohjK60/img.png&quot; data-alt=&quot;각 모델 별 f1_score과 accuracy_score&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3vk9Z/btsCyvH0DCf/Nvjrv4a6goLzACMiohjK60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3vk9Z%2FbtsCyvH0DCf%2FNvjrv4a6goLzACMiohjK60%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;647&quot; height=&quot;154&quot; data-origin-width=&quot;647&quot; data-origin-height=&quot;154&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;각 모델 별 f1_score과 accuracy_score&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;f1_score하고 macro_f1의 점수는 이렇게 나왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 점수를 보니 모든 모델 중에서 macro_f1_score 점수가 가장 높은 모델은 RandomForestClassifier모델이고, accuracy_score 기준 또한 RandomForestClassifier가 점수가 높게 나온 것을 알 수 있다.&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;pre id=&quot;code_1703397692110&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import learning_curve

# 모델, 특성, 타겟 데이터를 사용하여 학습 곡선 생성 , cv=5로 교차검정 5번 수행
train_sizes, train_scores, test_scores = learning_curve(
    rfc, x_resampled, y_resampled, cv = 5, train_sizes=np.linspace(0.1, 1.0, 10))
    
# 훈련 세트와 테스트 세트의 성능 평균 및 표준 편차 계산
train_scores_mean = np.mean(train_scores, axis=1)
train_scores_std = np.std(train_scores, axis=1)
test_scores_mean = np.mean(test_scores, axis=1)
test_scores_std = np.std(test_scores, axis=1)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1703397742431&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 학습 곡선 그리기
plt.figure(figsize=(10, 6))
plt.title(&quot;Learning Curve&quot;)
plt.xlabel(&quot;Training examples&quot;)
plt.ylabel(&quot;Score&quot;)
plt.grid()

plt.fill_between(train_sizes, train_scores_mean - train_scores_std,
                 train_scores_mean + train_scores_std, alpha=0.1, color=&quot;r&quot;)
plt.fill_between(train_sizes, test_scores_mean - test_scores_std,
                 test_scores_mean + test_scores_std, alpha=0.1, color=&quot;g&quot;)
plt.plot(train_sizes, train_scores_mean, 'o-', color=&quot;r&quot;, label=&quot;Training score&quot;)
plt.plot(train_sizes, test_scores_mean, 'o-', color=&quot;g&quot;, label=&quot;Cross-validation score&quot;)

plt.legend(loc=&quot;best&quot;)
plt.show()&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;692&quot; data-origin-height=&quot;434&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOSRum/btsCEJznsUk/CCPs0LkNtd5YuGhZgJByk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOSRum/btsCEJznsUk/CCPs0LkNtd5YuGhZgJByk0/img.png&quot; data-alt=&quot;RandomForestClassifier 학습 곡선&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOSRum/btsCEJznsUk/CCPs0LkNtd5YuGhZgJByk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOSRum%2FbtsCEJznsUk%2FCCPs0LkNtd5YuGhZgJByk0%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;556&quot; height=&quot;349&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;434&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;RandomForestClassifier 학습 곡선&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점수가 가장 높았던 RandomForestClassifier 에 대해서 학습곡선을 그려서 학습이 잘되었는지, 과대적합인지, 과소적합인지를 확인을 해본 결과, Cross-Validation Score에 대해서는 점진적 상승을 일으키지만, Training Score가 1로 적합이 되어있는 형태인 과대적합 형태로 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 과대적합은 &lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;모델이 훈련 데이터에 대해 너무 맞춰져서 새로운 데이터에 대한 일반화 성능이 떨어져서 생긴 것이다. 이러한 과대적합을 해결하기 위해서는 모델에 대한 단순화를 수행을 해야한다. 먼저 모델에 대한 하이퍼파라미터에 대해서 최적의 값을 찾아 과대적합이 해결되는지 확인을 하도록 한다. 우리가 고쳐야 할 하이퍼파라미터 종류는 아래와 같다.&lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&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;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;랜덤포레스트 하이퍼파리미터의 종류&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;n_estimators:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #374151; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;의사결정나무의 개수를 지정합니다. 많은 트리를 사용하면 모델이 더 강력해지지만, 계산 비용이 증가하게 됩니다. 기본값은 100입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #374151; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;criterion:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #374151; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;노드의 분할 기준을 지정합니다. &quot;gini&quot; 또는 &quot;entropy&quot; 중에서 선택할 수 있습니다. 기본값은 &quot;gini&quot;입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #374151; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;max_depth:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #374151; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 의사결정나무의 최대 깊이를 제한합니다. 더 깊은 트리는 더 복잡한 모델을 생성할 수 있지만, 계산 비용이 증가합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #374151; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;min_samples_split:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #374151; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;노드를 분할하기 위한 최소한의 샘플 수를 지정합니다. 이 수보다 작으면 더 이상 분할하지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #374151; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;min_samples_leaf:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #374151; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리프 노드가 가져야 하는 최소한의 샘플 수를 지정합니다.&lt;/li&gt;
&lt;/ul&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;다음 글에서 다른 모델에 대한 학습곡선 그림과 각 모델에 대한 하이퍼퍼라미터 튜닝 및 그리드 서치를 통한 최적의 하이퍼파라미터 찾는 방법을 수행하며, 머신러닝 모델이 아닌 딥러닝 모델인 Tensorflow Dense를 사용하여 모델을 만드는 것을 수행해 볼 것이다.&lt;/p&gt;</description>
      <author>DataKwon</author>
      <guid isPermaLink="true">https://koy0911.tistory.com/6</guid>
      <comments>https://koy0911.tistory.com/6#entry6comment</comments>
      <pubDate>Sun, 24 Dec 2023 15:24:24 +0900</pubDate>
    </item>
    <item>
      <title>Daicon 경진대회 - 학습 플랫폼 이용자 구독 갱신 예측 EDA 및 통계분석</title>
      <link>https://koy0911.tistory.com/5</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Daicon 학습 플랫폼 이용자 구독 갱신 예측 해커톤이 열려서 참여를 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(데이터 출처: &lt;a href=&quot;https://dacon.io/competitions/official/236179/overview/description&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dacon.io/competitions/official/236179/overview/description&lt;/a&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;코딩 환경은 Jupyter Notebook을 통해서 수행하였다.&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;/p&gt;
&lt;pre id=&quot;code_1703123947586&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
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
from matplotlib import rc
rc('font', family = 'Malgun Gothic')
plt.rcParams['axes.unicode_minus']= False&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;그 후 저장해둔 데이터 csv파일을 들고와준다.&lt;/p&gt;
&lt;pre id=&quot;code_1703123991381&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;train_data = pd.read_csv('./dataset/subscription/train.csv')
test_data = pd.read_csv('./dataset/subscription/test.csv')
result_data = pd.read_csv('./dataset/subscription/sample_submission.csv')&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;이렇게 들고온 데이터의 열이 무엇이 있는지 파악을 하기 위해 .info()를 사용하여 출력해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1703124037924&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;print(train_data.info(), '\n')
print(test_data.info())&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;471&quot; data-origin-height=&quot;785&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDbT6n/btsCpy6emZN/JD3ifejE1RkLteEbx0HCi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDbT6n/btsCpy6emZN/JD3ifejE1RkLteEbx0HCi0/img.png&quot; data-alt=&quot;불러온 데이터의 열&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDbT6n/btsCpy6emZN/JD3ifejE1RkLteEbx0HCi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDbT6n%2FbtsCpy6emZN%2FJD3ifejE1RkLteEbx0HCi0%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;368&quot; height=&quot;613&quot; data-origin-width=&quot;471&quot; data-origin-height=&quot;785&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;불러온 데이터의 열&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;* 데이터의 열의 내용&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;subscription_duration: 사용자가 서비스에 가입한 기간 (월)&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;recent_login_time: 사용자가 마지막으로 로그인한 시간 (일)&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;average_login_time: 사용자의 일반적인 로그인 시간&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;average_time_per_learning_session: 각 학습 세션에 소요된 평균 시간 (분)&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;monthly_active_learning_days: 월간 활동적인 학습 일수&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;total_completed_courses: 완료한 총 코스 수&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;recent_learning_achievement: 최근 학습 성취도&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;abandoned_learning_sessions: 중단된 학습 세션 수&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;community_engagement_level: 커뮤니티 참여도&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;preferred_difficulty_level: 선호하는 난이도&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;subscription_type: 구독 유형&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;customer_inquiry_history: 고객 문의 이력&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;payment_pattern 사용자의 지난 3개월 간의 결제 패턴을 10진수로 표현한 값.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;7: 3개월 모두 결제함&lt;/li&gt;
&lt;li&gt;6: 첫 2개월은 결제했으나 마지막 달에는 결제하지 않음&lt;/li&gt;
&lt;li&gt;5: 첫 달과 마지막 달에 결제함&lt;/li&gt;
&lt;li&gt;4: 첫 달에만 결제함&lt;/li&gt;
&lt;li&gt;3: 마지막 2개월에 결제함&lt;/li&gt;
&lt;li&gt;2: 가운데 달에만 결제함&lt;/li&gt;
&lt;li&gt;1: 마지막 달에만 결제함&lt;/li&gt;
&lt;li&gt;0: 3개월 동안 결제하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;target: 사용자가 다음 달에도 구독을 계속할지 (1) 또는 취소할지 (0)를 나타냄&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;자세한 열의 목록은 이렇게 이루어져 있다. 이를 통해서 데이터에 대해서 EDA를 수행할 것이다.&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;열 중에서는 user_id 라는 열이 존재하는데 이는 개개인의 사람들에 대한 고윳값을 나타내기 때문에 EDA 및 데이터분석,&amp;nbsp; 모델링을 할 때 불필요하기 때문에 이를 삭제를 수행한다.&lt;/p&gt;
&lt;pre id=&quot;code_1703124350913&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# train, test_data에 있는 id는 고유값이라서 모델학습때 사용하지 않으므로 삭제
train_data.drop('user_id', axis = 1, inplace = True)
test_data.drop('user_id', axis = 1, inplace = True)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 데이터에 대해서 중복되는 값이 있는지 확인을 해본다.&lt;/p&gt;
&lt;pre id=&quot;code_1703144996171&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;train_data[train_data.duplicated()] #train_data에 대해서 중복되는 값이 있는지 확인&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;706&quot; data-origin-height=&quot;43&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Jhnq3/btsCl1P2W0h/unbSDZVK0Rt2qekEGx0s4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Jhnq3/btsCl1P2W0h/unbSDZVK0Rt2qekEGx0s4k/img.png&quot; data-alt=&quot;train_data에 중복값 존재 여부&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Jhnq3/btsCl1P2W0h/unbSDZVK0Rt2qekEGx0s4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJhnq3%2FbtsCl1P2W0h%2FunbSDZVK0Rt2qekEGx0s4k%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;706&quot; height=&quot;43&quot; data-origin-width=&quot;706&quot; data-origin-height=&quot;43&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;train_data에 중복값 존재 여부&lt;/figcaption&gt;
&lt;/figure&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;다음으로 수치형 데이터의 열과 범주형 데이터의 열을 리스트 형태로 저장한 후, train_data에서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수치형 데이터의 통계치를 확인을 해본다.&lt;/p&gt;
&lt;pre id=&quot;code_1703124600274&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 수치형 데이터 열의 이름을 리스트형태로 col_num에 저장
col_num = train_data.select_dtypes(exclude='object').columns.tolist()
# 범주형 데이터 열의 이름을 리스트 형태로 col_cat에 저장
col_cat = train_data.select_dtypes(include='object').columns.tolist()

# train_data중 수치형에 대한 통계치 파악
train_data[col_num].describe()&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;986&quot; data-origin-height=&quot;259&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ucn3G/btsCq80sZTq/F09sKqWHzTywpeTrC0133K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ucn3G/btsCq80sZTq/F09sKqWHzTywpeTrC0133K/img.png&quot; data-alt=&quot;train_data의 수치형 데이터 통계치&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ucn3G/btsCq80sZTq/F09sKqWHzTywpeTrC0133K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fucn3G%2FbtsCq80sZTq%2FF09sKqWHzTywpeTrC0133K%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;986&quot; height=&quot;259&quot; data-origin-width=&quot;986&quot; data-origin-height=&quot;259&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;train_data의 수치형 데이터 통계치&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;여기서 확인해 볼수 있는 것은&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;최근 로그인한 시간이 29일 전인 사람이 존재&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;-&amp;gt; 29일 전이면 이 사람은 학습을 다한것인지중도 포기한것인지 확인 필요&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&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;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;평균 로그인 시간이 2.3분인 사람이 존재&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;-&amp;gt; 평균 로그인 시간이 2.3분이면 이 사람은 학습에 참여를 제대로 한 것인가?&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;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;학습 세션 소요된 평균 시간이 거의 0분인 사람이 있고, 503분이 걸린 사람이 존재한다&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;-&amp;gt; 503분이 소요된 사람은 학습을 제대로 참여한 것이 맞는지 확인이 필요하다.&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;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;완료된 총 코스의 수가 1인 사람이 존재&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;-&amp;gt; 왜 1개를 들었는지? 확인이 필요하다. 최근 가입인원일 가능성 존재&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;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;그 후 수치형 &lt;/span&gt;데이터에 대한 분포를 파악해보기 위해 히스토그램을 그려본다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1703126067472&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 수치형 데이터에 대한 히스토그램 출력
i = 0
plt.figure(figsize=(12, 8))

for col in col_num:
    i += 1
    plt.subplot(4,3, i)
    sns.distplot(train_data[col], bins= 50)
plt.tight_layout()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;765&quot; data-origin-height=&quot;519&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bs7OO1/btsCoBoMtE1/7geOhHedJqggkuYNqknEJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bs7OO1/btsCoBoMtE1/7geOhHedJqggkuYNqknEJk/img.png&quot; data-alt=&quot;수치형 데이터에 대한 히스토그램&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bs7OO1/btsCoBoMtE1/7geOhHedJqggkuYNqknEJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbs7OO1%2FbtsCoBoMtE1%2F7geOhHedJqggkuYNqknEJk%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;391&quot; data-origin-width=&quot;765&quot; data-origin-height=&quot;519&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;수치형 데이터에 대한 히스토그램&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;히스토그램을 살펴보니 average_login_time과 recent_learning_achievement, total_completed_courses가 정규분포를 따르는 것으로 보이며, submission_duration과 recent_login_time, monthly_active_learning_days는 균등분포를 따르는 것으로 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지 average_time_per_learning_sessions는 오른쪽으로 꼬리가 긴 양수 왜도가 나타났으며, abandoned_learning_sessions과 customer_inquiry_history는 데이터가 float 정수형이 아닌 int 수치형이기 때문에 정규분포를 따르는 것일지라도 히스토그램의 뿔이 여러개가 나오는 것으로 보이는 것 같다.&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;이러한 정보 이외에 알아볼 수 있는 정보로는 target 변수가 불균형하게 차이가 존재하는 것을 파악할 수 있으며payment_pattern은 고르게 나타나있고, community_engagement_level가 높은 사람이 많다는 것을 알 수 있다.&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;데이터가 정규분포를 따르는지에 대해서 통계치로 알아보기 위해서 주로 사용하는 통계검정은 Shapiro_wilk검정이지만, Shapiro_wilk 정규성 검정은 데이터의 개수가 5000개 이상으로 넘어가면, 신뢰성이 떨어지기 때문에 다른 유사한 검정인 앤더슨-달링 검정을 사용하도록 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1703127800426&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from scipy.stats import anderson #앤더슨 달링 검정을 사용하기 위한 모듈 들고오기

for col in col_num:
    result = anderson(train_data[col])
    
    print(f&quot;Results for {col} column: &quot;)
    print(&quot;Statistic: &quot;, result.statistic)
    print(&quot;Critical Values: &quot;, result.critical_values)
    print(&quot;Significance Levels: &quot;, result.significance_level)
    if result.statistic &amp;gt; result.critical_values[2]:
        print(f&quot;{col}은 정규분포를 따르지 않습니다.&quot;, '\n')
    else:
        print(&quot;f{col}은 정규분포를 따릅니다.&quot;, '\n')&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;408&quot; data-origin-height=&quot;823&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOSTq2/btsCk9mwGc2/48vqcd5aJET7ABBA0L5RM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOSTq2/btsCk9mwGc2/48vqcd5aJET7ABBA0L5RM1/img.png&quot; data-alt=&quot;수치형 데이터에 대한 앤더슨 달링 정규성 검정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOSTq2/btsCk9mwGc2/48vqcd5aJET7ABBA0L5RM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOSTq2%2FbtsCk9mwGc2%2F48vqcd5aJET7ABBA0L5RM1%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;320&quot; height=&quot;645&quot; data-origin-width=&quot;408&quot; data-origin-height=&quot;823&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;수치형 데이터에 대한 앤더슨 달링 정규성 검정&lt;/figcaption&gt;
&lt;/figure&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;average_login_time, recent_learning_achievement&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;*정규분포를 따르지 않는 데이터&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;subscription_duration, recent_login_time, average_time_per_learning_session, monthly_active_learning_days, total_completed_courses, abandoned_learning_sessions, community_engagement_level, customer_inquiry_history, payment_pattern, target 으로 이루어져 있었다.&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;정규분포를 따르지 않는 데이터 중 payment_pattern, community_engagement_level은 수치형 데이터로 되어있지만 실상 범주형 변수 형태이며, target은 우리가 예측을 해야하는 종속변수이므로 정규분포를 따르지 않았다고 하더라도 문제가 없다.&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;그러므로 payment_pattern과 community_engagement_level은 범주형으로 변환해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1703128953182&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;train_data['payment_pattern'] = train_data['payment_pattern'].astype('object')
train_data['community_engagement_level'] = train_data['community_engagement_level'].astype('object')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;customer_inquiry_history 변수도 얼핏보면 범주형처럼 보이지만, 문의를 넣은 횟수라는 수치형 데이터이기 때문에 변환을 시켜주지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 변한 col_num과 col_cat 이라는 수치, 범주형 변수 열을 리스트에 저장한 값을 갱신을 해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1703139970953&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 앞에 지정한 col_num과 col_cat 갱신
col_num = train_data.select_dtypes(exclude='object').columns.tolist()
col_cat = train_data.select_dtypes(include='object').columns.tolist()&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;/p&gt;
&lt;pre id=&quot;code_1703139916875&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;i = 0
plt.figure(figsize = (18, 12))

for col in col_num:
    i += 1
    plt.subplot(6,2, i)
    sns.barplot(x = train_data['community_engagement_level'], y = train_data[col],data= train_data)

    plt.tight_layout()
plt.show()&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;956&quot; data-origin-height=&quot;619&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HljTd/btsCpd2SOXH/aY4XTK4Qv5PYUmGinEIXKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HljTd/btsCpd2SOXH/aY4XTK4Qv5PYUmGinEIXKk/img.png&quot; data-alt=&quot;커뮤니티 참여도 별 수치형 변수에 대한 막대그래프&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HljTd/btsCpd2SOXH/aY4XTK4Qv5PYUmGinEIXKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHljTd%2FbtsCpd2SOXH%2FaY4XTK4Qv5PYUmGinEIXKk%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;755&quot; height=&quot;489&quot; data-origin-width=&quot;956&quot; data-origin-height=&quot;619&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;커뮤니티 참여도 별 수치형 변수에 대한 막대그래프&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;community_engagement_level에 따른 수치형 변수에 대한 차이를 확인해보니, 대부분의 변수에서는 차이가 없다고 나타났지만, average_time_per_learning_session과 total_completed_courses에서는 차이가 존재했다.&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;먼저 community_engagement_level가 낮을수록 total_completed_courses가 적다는 것을 파악을 할 수 있고, average_time_per_learning_session도 community_engagement_level이 낮을수록 수치가 낮다는 것을 알 수 있다.&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;그 다음으론 선호난이도 preferred_difficulty_level별 막대그래프로 비교를 해볼 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1703140325470&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;i = 0
plt.figure(figsize = (18, 12))

for col in col_num:
    i += 1
    plt.subplot(6,2, i)
    sns.barplot(x = train_data['preferred_difficulty_level'], y = train_data[col],data= train_data)

plt.tight_layout()
plt.show()&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;956&quot; data-origin-height=&quot;548&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RkQRK/btsClZEyhdi/mQnl8HXsU8pnwzuwZouEMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RkQRK/btsClZEyhdi/mQnl8HXsU8pnwzuwZouEMK/img.png&quot; data-alt=&quot;선호난이도 별 수치형 변수에 대한 막대그래프&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RkQRK/btsClZEyhdi/mQnl8HXsU8pnwzuwZouEMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRkQRK%2FbtsClZEyhdi%2FmQnl8HXsU8pnwzuwZouEMK%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;759&quot; height=&quot;435&quot; data-origin-width=&quot;956&quot; data-origin-height=&quot;548&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;선호난이도 별 수치형 변수에 대한 막대그래프&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;막대그래프를 확인해보니 다른 변수와는 차이가 나는 것은 확인이 되지 않지만, average_time_per_learning_session과&amp;nbsp; total_completed_courses가 차이가 존재하는 것으로 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선호 난이도가 높을수록 total_completed_courses가 낮아지는 것을 확인할 수 있고, average_time_per_learning_sessions도 선호 난이도가 높을 수록 낮게 나왔다. 일반적이라면 preferred_difficulty_level이 높을수록average_time_per_learning_session이 높아야 할 것 같지만 낮게 나와 나의 예상과는 다른 값이었다.&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;그래서 한번 고민해본 결과 자신의 선호 난이도가 높으면 그 사람은 그 분야에 대해서 숙달된 사람일 것이라 생각을 하였으며, 숙달된 만큼 average_time_per_learning_session이 낮게 나온것이라 생각하게 되었다.&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;마지막으로는 구독타입 subscription_type별 수치형 변수에 대한 막대그래프를 그려볼 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1703140960433&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;i = 0
plt.figure(figsize = (18, 12))

for col in col_num:
    i += 1
    plt.subplot(6,2, i)
    sns.barplot(x = train_data['subscription_type'], y = train_data[col],data= train_data)

plt.tight_layout()
plt.show()&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;960&quot; data-origin-height=&quot;550&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blVIDY/btsCpBQbxVz/KK1qmS0MhKfUHCSiqqc4g1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blVIDY/btsCpBQbxVz/KK1qmS0MhKfUHCSiqqc4g1/img.png&quot; data-alt=&quot;구독 타입 별 수치형 변수에 대한 막대그래프&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blVIDY/btsCpBQbxVz/KK1qmS0MhKfUHCSiqqc4g1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblVIDY%2FbtsCpBQbxVz%2FKK1qmS0MhKfUHCSiqqc4g1%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;713&quot; height=&quot;408&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;550&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;구독 타입 별 수치형 변수에 대한 막대그래프&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;막대그래프를 확인해보니 다른 막대그래프와 같이 다른변수에는 차이가 없지만 average_time_per_learning_session과 total_completed_courses에서만 차이가 존재했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;total_completed_courses는 구독이 premium인 사람이 basic인 사람보다 높게 나왔는데, 이는 모든 구독 가격이 basic보다 premium이 더 높기 때문에 학습을 하는 사람들은 자신이 사용을 한 돈에 따라 참여율에 차이가 존재한다는 것을 알 수 있었으며, average_time_per_learning_session또한 premium인 사람이 참여율이 더 높기 떄문에 premium이 더 높을 수 밖에 없었을 것이다.&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구독 여부에 따른 완료 코스 수의 차이를 검정해본다.&lt;/p&gt;
&lt;pre id=&quot;code_1703143322118&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 통계검정 -&amp;gt; 난이도 선택에 따른 코스 완료수 차이 검정
from scipy.stats import f_oneway
group_v1 = train_data[train_data['preferred_difficulty_level']=='Low']['total_completed_courses']
group_v2 = train_data[train_data['preferred_difficulty_level']=='Medium']['total_completed_courses']
group_v3 = train_data[train_data['preferred_difficulty_level']=='High']['total_completed_courses']

f_statistic, p_value = f_oneway(group_v1, group_v2, group_v3)
print(f'F-Statistic: {f_statistic}, P-Value : {p_value}')&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;469&quot; data-origin-height=&quot;28&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dZrNHa/btsCtnJ0YWc/ZohR0clkeEACuoc4tPwYz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dZrNHa/btsCtnJ0YWc/ZohR0clkeEACuoc4tPwYz1/img.png&quot; data-alt=&quot;난이도 선택에 따른 코스 완료수 차이 검정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dZrNHa/btsCtnJ0YWc/ZohR0clkeEACuoc4tPwYz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdZrNHa%2FbtsCtnJ0YWc%2FZohR0clkeEACuoc4tPwYz1%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;469&quot; height=&quot;28&quot; data-origin-width=&quot;469&quot; data-origin-height=&quot;28&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;난이도 선택에 따른 코스 완료수 차이 검정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;p-value값이 4.3195e-187로 유의수준 0.05하에 귀무가설이 기각이 되므로 난이도 선택에 따른 완료 코스 수에는 차이가&amp;nbsp; 존재하는 것을 알 수 있다. 이러한 방법으로 차이가 존재하는지 확인해본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 어떤 그룹 간에 차이가 나는지 확인할 수도 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1703145382322&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 터커의 다중비교 검정
from statsmodels.stats.multicomp import pairwise_tukeyhsd

tukey_results = pairwise_tukeyhsd(endog=train_data['total_completed_courses'],
                                 groups=train_data['preferred_difficulty_level'],
                                 alpha = 0.05)

print(tukey_results)&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;380&quot; data-origin-height=&quot;123&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ojGfe/btsCokVUyms/UUItFtBWcQQjgPTOZ6njvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ojGfe/btsCokVUyms/UUItFtBWcQQjgPTOZ6njvK/img.png&quot; data-alt=&quot;터커의 다중비교 검정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ojGfe/btsCokVUyms/UUItFtBWcQQjgPTOZ6njvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FojGfe%2FbtsCokVUyms%2FUUItFtBWcQQjgPTOZ6njvK%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;380&quot; height=&quot;123&quot; data-origin-width=&quot;380&quot; data-origin-height=&quot;123&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;터커의 다중비교 검정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 검정을 통해 선호난이도가 High와 Medium은 차이가 없지만, High와 Low, Medium과 Low에는 차이가 존재한다는 것을 알 수 있다.&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;이제 수치형 데이터에 대해서 boxplot을 그려보면서 이상치가 존재하는지 간접적으로 확인해 볼 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1703141869373&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 수치형 데이터에서 boxplot을 그려 이상치가 있는지 간접적으로 파악해본다.
i = 0
plt.figure(figsize = (18, 12))

for col in col_num:
    i += 1
    plt.subplot(4,3, i)
    sns.boxplot(x = col, data = train_data, palette = 'husl')

plt.tight_layout()
plt.show()&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;957&quot; data-origin-height=&quot;478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L4tM9/btsCr6IKmLw/5oKfekQb69Rc0nNkr1ZIC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L4tM9/btsCr6IKmLw/5oKfekQb69Rc0nNkr1ZIC1/img.png&quot; data-alt=&quot;수치형 변수에 대한 boxplot(target 미포함)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L4tM9/btsCr6IKmLw/5oKfekQb69Rc0nNkr1ZIC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL4tM9%2FbtsCr6IKmLw%2F5oKfekQb69Rc0nNkr1ZIC1%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;708&quot; height=&quot;354&quot; data-origin-width=&quot;957&quot; data-origin-height=&quot;478&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;수치형 변수에 대한 boxplot(target 미포함)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;boxplot을 해본 결과 데이터에 대한 이상치가 존재할 것 같은 데이터는 average_time_per_learning_session, average_login_time, total_completed_courses, recent_learning_achievement, abandoned_learning_sessions, customer_inquiry_history가 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 이상치는 데이터에 대한 IQR 기준으로써의 이상치이므로 이상치가 아닌 이상치 후보일 뿐 진짜 이상치가 아닐수도 있다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 이상치를 정확하게 확인해보기 위해서 train_data에서 test_data셋의 최대 최소값을 기준으로 값이 벗어나는게 존재하는지 확인하여 진짜 이상치를 한번 탐지해보도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 방법으로 이상치를 검사하기전 train_data와 test_data의 분포가 유사한지 검증을 한 후 분포가 유사하다면 위 방법을 사용해서 이상치를 탐지할 수 있다.&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;먼저 train_data셋과 test_data셋의 분포에 차이가 있는지에 대해서 K-S 검정을 수행한다.&lt;/p&gt;
&lt;pre id=&quot;code_1703209929119&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#어떤 변수에서 차이 있는가?
from scipy import stats

feature_list = test_data.columns.values.tolist()
for feature in feature_list:
    statistics, p_value = stats.kstest(train_data[feature], test_data[feature])
    if statistics &amp;gt; 0.1 and p_value &amp;lt; 0.05:
        print(f'K-S Test Value: {statistics:.2f}, with p-value {p_value:.2f}, the feature, {feature}')&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;571&quot; data-origin-height=&quot;30&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FeX4O/btsCsnqzFox/cTK9gkDw7Cb0nzP9y34ZY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FeX4O/btsCsnqzFox/cTK9gkDw7Cb0nzP9y34ZY1/img.png&quot; data-alt=&quot;train_data, test_data의 K-S 검정 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FeX4O/btsCsnqzFox/cTK9gkDw7Cb0nzP9y34ZY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFeX4O%2FbtsCsnqzFox%2FcTK9gkDw7Cb0nzP9y34ZY1%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;571&quot; height=&quot;30&quot; data-origin-width=&quot;571&quot; data-origin-height=&quot;30&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;train_data, test_data의 K-S 검정 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;train_data, test_data의 K-S검정 결과 p-value 0.00으로 유의수준 0.05하 귀무가설을 기각, 대립가설을 채택하므로 train_data, test_data간의 분포에 차이가 존재한다. train_data와 test_data의 분포에 차이가 존재하는 변수는&amp;nbsp;preferred_difficulty_level에서 차이가 존재한다는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, preferred_difficulty_level을 제외한 나머지 변수들에서는 분포에 대한 차이가 없다는 것을 뜻한다.&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;이제 train_data에 test_data의 최대 최소값을 기준으로 벗어나는 값이 존재하는지 확인을 해보도록 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1703210355674&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#train, test set에서 사용할 변수 지정
features = ['subscription_duration', 'recent_login_time', 'average_login_time',
       'average_time_per_learning_session', 'monthly_active_learning_days',
       'total_completed_courses', 'recent_learning_achievement',
       'abandoned_learning_sessions', 'community_engagement_level',
       'preferred_difficulty_level', 'subscription_type',
       'customer_inquiry_history', 'payment_pattern']

# train_data의 히스토그램을 그린 후 test_data의 변수별 최대 최소값을 선으로 표시함
f, ax = plt.subplots(5, 3, figsize=(10, 10))
ax = ax.ravel()
for ax, f in zip(ax, features):
    ax.hist(train_data[f], bins=100, density=True)
    ax.set_ylabel('density')
    
    ax.axvline(test_data[f].min(), color='r')
    ax.axvline(test_data[f].max(), color='r')
    
plt.tight_layout()
plt.show()&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;693&quot; data-origin-height=&quot;697&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vAryY/btsCsfzyZTS/PG94JGNJ1zfpDq4u6ORYDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vAryY/btsCsfzyZTS/PG94JGNJ1zfpDq4u6ORYDk/img.png&quot; data-alt=&quot;train_data에 대한 히스토그램과 test_data의 변수별 최대 최소값의 선&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vAryY/btsCsfzyZTS/PG94JGNJ1zfpDq4u6ORYDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvAryY%2FbtsCsfzyZTS%2FPG94JGNJ1zfpDq4u6ORYDk%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;603&quot; height=&quot;606&quot; data-origin-width=&quot;693&quot; data-origin-height=&quot;697&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;train_data에 대한 히스토그램과 test_data의 변수별 최대 최소값의 선&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;train_data에 대한 히스토그램에서 test_data의 변수별 최대 최소값의 선을 보니 선을 벗어나는 값이 존재하지 않아 보인다.&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;이로써 데이터에 대해서 알수 있는 정보는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. train_data와 test_data에서의 분포는 preferred_difficulty_level을 제외하고 차이가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. average_time_per_learning_session은 오른쪽으로 꼬리가 긴 양수 왜도 형태를 띈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. train_data의 boxplot결과에서는 이상치가 존재하는 것 처럼 보였지만 train_data에서 test_data의&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;4. 커뮤니티 참여도가 낮을수록 총 학습 코스 수가 적다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 커뮤니티 참여도가 낮을수록 &lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;각 학습 세션에 소요된 평균 시간&lt;/span&gt; 도 낮다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;6. 선호 난이도가 높을수록 완료한 총 코스 수가 낮다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;7. 선호 난이도가 높을수록 각 학습 세션에 소요된 평균 시간이 낮다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;8. 완료한 총 코스 수는 구독 유형이 Premium인 사람이 Basic인 사람보다 높다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;9. 각 학습 세션에 소요된 평균 시간은 Premium인 사람이 Basic인 사람보다 높다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;10. target변수에 대해서 데이터 불균형이 존재한다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 데이콘 학습플랫폼 구독 갱신 여부 예측 데이터에 대한 EDA 및 통계 분석을 마쳤다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다음에는 이러한 EDA 기반으로 데이터를 전처리를 하여 모델을 만들도록 하겠다.&lt;/p&gt;</description>
      <category>데이터 분석</category>
      <author>DataKwon</author>
      <guid isPermaLink="true">https://koy0911.tistory.com/5</guid>
      <comments>https://koy0911.tistory.com/5#entry5comment</comments>
      <pubDate>Fri, 22 Dec 2023 11:19:11 +0900</pubDate>
    </item>
    <item>
      <title>캡스톤 디자인 - Raspberry Pi4를 이용한 실시간 화재 탐지 카메라</title>
      <link>https://koy0911.tistory.com/4</link>
      <description>&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;이러한 화재가 얼마나 자주 발생하고, 피해액이 얼마인지 소방통계청(&lt;a href=&quot;https://www.nfds.go.kr/stat/general.do&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.nfds.go.kr/stat/general.do&lt;/a&gt;)에서 통계를 확인해보았다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1223&quot; data-origin-height=&quot;227&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yLYjz/btsCl0IEUlq/WZIvFIESGzt7qwEWOQsdG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yLYjz/btsCl0IEUlq/WZIvFIESGzt7qwEWOQsdG1/img.png&quot; data-alt=&quot;소방통계청 2020년~2023년12월까지 화재통계&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yLYjz/btsCl0IEUlq/WZIvFIESGzt7qwEWOQsdG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyLYjz%2FbtsCl0IEUlq%2FWZIvFIESGzt7qwEWOQsdG1%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;1223&quot; height=&quot;227&quot; data-origin-width=&quot;1223&quot; data-origin-height=&quot;227&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;소방통계청 2020년~2023년12월까지 화재통계&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LOjfv/btsCkpCa587/uqcu9UctDSdO3U6lZRRIz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LOjfv/btsCkpCa587/uqcu9UctDSdO3U6lZRRIz0/img.png&quot; data-alt=&quot;2020년부터 2023년 12월까지 화재건수&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LOjfv/btsCkpCa587/uqcu9UctDSdO3U6lZRRIz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLOjfv%2FbtsCkpCa587%2Fuqcu9UctDSdO3U6lZRRIz0%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;264&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;264&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2020년부터 2023년 12월까지 화재건수&lt;/figcaption&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;이렇게 2020년부터 2023년까지 화재 발생이 많고 피해액도 크다는 것을 확인할 수 있었다.&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;이러한 화재탐지 카메라를 만들기 위해 사용한 물품으로 AI를 탑재시킬 수 있는 모듈인 Raspberry pi4를 사용하였으며, 카메라는 대학생이어서 큰 돈을 사용하지 못한다는 조건으로 기본적인 Raspberry V2 카메라를 사용하였다.&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;먼저 Raspberry pi4에 카메라를 연동을 시켜주는 것으로 프로젝트를 수행한다.&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;a href=&quot;https://velog.io/@addps5012/%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4-V2-%EC%B9%B4%EB%A9%94%EB%9D%BC-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@addps5012/%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4-V2-%EC%B9%B4%EB%A9%94%EB%9D%BC-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0&lt;/a&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;이제 카메라를 통해서 화재를 실시간으로 감지를 해야하는데, 많은 모델들이 존재하지만, 그 중 우리는 인공지능 모델 중 Ultralytics에서 만든 YOLO V8을 사용하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;YOLO V8에 대한 간단한 설명으로는 아래 사이트를 참고하기를 바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(&lt;a href=&quot;https://yolov8.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://yolov8.com/&lt;/a&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;s&gt;Raspberry pi4에 yolov8을 사용하기 위해 밑작업이 존재하지만, 실수로 밑작업에 대해서 남겨둔 코드를 저장하지 않았는지 찾을 수 없었다.(직접 찾아주길 바란다, 덕분에 코드를 저장하는 습관이 생겼다.)&lt;/s&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;Raspberry pi4에 직접 모델을 학습시켜서 사용하기에는 Raspberry pi4는 모델학습을 하기에는 모듈성능이 좋지 않기 때문에 외부 컴퓨터에서 직접 모델을 학습을 시킨 후, 학습시킨 모델(Pretrained Model)을 들고와서 Raspberry pi4에 넣어주는 방법을 사용을 하였다.&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;YOLO V8의 모델에서 내가 원하는 탐지를 시켜주기 위해서는 모델에 내가 원하는 객체를 탐지할 수 있게 이미지 라벨링이 되어있는 데이터가 필요하다. 이러한 데이터를 얻기 위해서 많은 곳에서 찾아본 결과 Roboflow에서 이미지 라벨링이 되어있는 데이터를 찾을 수 있었다. (원하는 라벨링된 이미지 찾는 사이트: &lt;a href=&quot;https://universe.roboflow.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://universe.roboflow.com/&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 다른사람이 직접 이미지 라벨링을 한 것을 들고와서 YOLO V8 모델에 학습을 시켜주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델 학습은 내가 가진 노트북이나 컴퓨터의 GPU가 좋지 않기 때문에 Google의 Colab에 gpu사용을 하여 학습을 시켰다.&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;Google colab에서 roboflow 데이터를 들고와서 YOLO V8학습시키는 코드&lt;/p&gt;
&lt;pre id=&quot;code_1703049594267&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;!nvidia-smi # NVIDIA GPU드라이버 및 GPU 관련 정보 확인

import os
HOME = os.getcwd()
print(HOME)  # colab 경로 확인


!pip install ultralytics==8.0.20 # YOLO를 포함한 객체 검출 및 CV 딥러닝 라이브러리 설치


import ultralytics # ultralytics 들고오기
ultralytics.checks() # ultralytics 정보 체크


!mkdir {HOME}/datasets # 경로에 datasets라는 디렉토리 생성
%cd {HOME}/datasets # 현재 디렉토리를 datasets로 변경
!pip install roboflow --quiet  # roboflow 라이브러리 설치 - quiet: 설치과정 출력 최소화

#roboflow데이터를 들고오기

from roboflow import Roboflow
rf = Roboflow(api_key=&quot;~~~~~~~~~&quot;)
project = rf.workspace(&quot;~~~~&quot;).project(&quot;~~~~~~~~~&quot;)
dataset = project.version(3).download(&quot;yolov8&quot;)
'''
~표시 한 것은 데이터 불러오기 위한 api_key 등 정보이기에 가려주었으며, 들고오는 데이터에 따라
달라지기 때문에 지워주었다. 들고오는 방법은 아래에 바로 알려주겠다.
'''&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 roboflow에서 데이터를 들고오는 방법에 대해서 알려줄 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에 roboflow universe라는 사이트에 들어가 내가 원하는 라벨링 된 데이터에 대해서 검색을 한 후, 검색결과 중 하나를 정해 들어간다. 그러면 오른쪽 위에 이미지 처럼 Download this Dataset이 있을 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;234&quot; data-origin-height=&quot;99&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blcxvS/btsCox0dopW/WbXKFOOk02V1gxBEyx2S7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blcxvS/btsCox0dopW/WbXKFOOk02V1gxBEyx2S7K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blcxvS/btsCox0dopW/WbXKFOOk02V1gxBEyx2S7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblcxvS%2FbtsCox0dopW%2FWbXKFOOk02V1gxBEyx2S7K%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;180&quot; height=&quot;76&quot; data-origin-width=&quot;234&quot; data-origin-height=&quot;99&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Download this Dataset을 누르면, Format과 show download code라고 나올것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;507&quot; data-origin-height=&quot;257&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WzC4b/btsCg5dC0u6/p4uff9rKImRvNhimLW0eY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WzC4b/btsCg5dC0u6/p4uff9rKImRvNhimLW0eY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WzC4b/btsCg5dC0u6/p4uff9rKImRvNhimLW0eY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWzC4b%2FbtsCg5dC0u6%2Fp4uff9rKImRvNhimLW0eY1%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;333&quot; height=&quot;169&quot; data-origin-width=&quot;507&quot; data-origin-height=&quot;257&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 Format에서 자신이 사용할 인공지능 모델을 선택해준다. 나는 YOLOv8을 사용하므로 YOLOv8을 선택해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 show download code가 선택되어있는데 이 설정 그대로 선택해주고 Continue를 눌러주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;download zip to computer는 컴퓨터에 위 사진을 전부 zip파일 형식으로 저장한다는 것이기에 이 사이트에서 바로 들고와서 사용하는 나는 이러한 설정이 불필요하다. Continue를 눌러주면 로딩창이 뜨며 기다려줘야한다.&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 alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;507&quot; data-origin-height=&quot;439&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xUgTk/btsCnLq9Enk/SslChc1rBMeJyISv9KBMK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xUgTk/btsCnLq9Enk/SslChc1rBMeJyISv9KBMK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xUgTk/btsCnLq9Enk/SslChc1rBMeJyISv9KBMK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxUgTk%2FbtsCnLq9Enk%2FSslChc1rBMeJyISv9KBMK1%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;306&quot; height=&quot;439&quot; data-origin-width=&quot;507&quot; data-origin-height=&quot;439&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;완료가 되면 이러한 코드가 뜨는데 이 코드를 복사해서 roboflow 데이터 불러오는 코드에 넣어서 실행시키면 된다.&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;이제 다시 YOLOv8모델 학습으로 돌아온다.&lt;/p&gt;
&lt;pre id=&quot;code_1703050753455&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;%cd {HOME}

# 이 코드를 통해서 모델을 학습을 시켜준다.
!yolo task=detect model=train model=yolov8n.pt data=/content/datasets/fire-and-smoke-detection-3/data.yaml epochs=100 imgsz=640 plots=True
'''
코드 세분해서 설명
model=train model=yolov8n.pt: YOLOv8 모델은 많은 pt가 존재한다.(pre-trained: 미리 학습된)
data=/content/datasets/fire-and-smoke-detection-3/data.yaml: roboflow에서 들고온 데이터
epochs=100: 100번 학습
'''&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 모델을 학습을 한다. 이때 참고하면 좋을 것은 pt에 대한 설명이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;725&quot; data-origin-height=&quot;276&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bb2fU7/btsCknLnFYU/D53MRWYNfWWQEYOfQJkywK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bb2fU7/btsCknLnFYU/D53MRWYNfWWQEYOfQJkywK/img.png&quot; data-alt=&quot;YOLO의 pt 종류&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bb2fU7/btsCknLnFYU/D53MRWYNfWWQEYOfQJkywK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbb2fU7%2FbtsCknLnFYU%2FD53MRWYNfWWQEYOfQJkywK%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;222&quot; data-origin-width=&quot;725&quot; data-origin-height=&quot;276&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;YOLO의 pt 종류&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;YOLO에는 미리 학습된 모델이 존재한다. 각자 s, m, l, x로 되어있는데 v8부터는 n도 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n: nano, s: small, m: medium, l: large, x: xlarge로 모델의 깊이와 관련이 있는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 하나를 선택해 Custom Data를 학습을 시켜서 모델을 만들면 되는 것이다.&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해서 화재에 대한 동영상을 colab에 넣고 직접 만든 모델을 적용시켜 탐지가 잘되는지 확인해보는 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1703051122352&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# colab에 넣은 비디오에 직접 만든 모델 pt를 적용시켜 잘 탐지하는지 검증한다.
# 비디오를 저장하고 비디오를 키면 비디오에 학습시킨 객체에 대해서 라벨링을 수행해준다.
!yolo task=detect mode=predict model=&quot;/content/runs/detect/train/weights/best.pt&quot; source=&quot;fire.mp4&quot; save=True&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 학습이 완료되었으면, best.pt라는 Custom Data로 학습시킨 YOLOv8 모델 파일을 저장하고, Raspberry pi4에&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;Raspberry pi4에 best.pt모델을 적절한 위치에 옮겨두었으면 이제 카메라에 이러한 모델을 적용시켜 실시간으로 화재를&amp;nbsp; 탐지할 수 있도록 적용을 시킬 것이다. Raspberry pi4 내부에는 기본적인 파이썬이 없기 때문에 Raspberry pi4 내부에 존재하는 텍스트 에디터인 Geany를 사용하여 파이썬 코드를 실행시켜 줄 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1703052955461&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from tkinter import *  # 알림창을 띄우기 위한 모듈
import tkinter.messagebox # 알림창 띄우기 위한 모듈
from ultralytics import YOLO  # ultralytics에서의 YOLO 모듈
import cv2 # 이미지 처리를 위한 모듈
import numpy as np  # 넘파이 모듈
import torch # torch 모듈
from time import time # time 모듈

#학습시킨 모델의 best.pt를 사용한다.(Geany 텍스트 에디터와 같은 위치에 best.pt 있어야한다.)
model = YOLO('best.pt') 

# 라즈베리파이에 연결한 카메라를 cap으로 지정
cap = cv2.VideoCapture(0)

#카메라 끄는 기본값 설정
ESC_KEY_CODE = 27
Q_KEY_CODE = ord('q')

#FPS 초기값
prev_time = 0
FPS = 10


# YOLOV8 실시간 카메라 출력 코드 - best.pt를 모델로 지정
wsshile True:
  ret, frame = cap.read()

  if not ret:
    break

    resized_frame = cv2.resize(frame, (640, 640))
    results = model.predict(resized_frame, show = True)

    # boundingbox count information: 바운딩 박스 정보
    result = results[0]

    #바운딩 박스가 1개 이상 나오면
    if len(result.boxes) &amp;gt; 0:
      #메세지 박스 출력
      tkinter.messagebox.showwarning('Detection!', 'Fire or Smoke Detection!')
      continue
    else:
      continue

    if cv2.waitkey(1) == ord('q'):
      break

#FPS 조절
while True:
  ret, frame = cap.read()
  current_time = time.time() - prev_time

  if (ret is True) and (current_time &amp;gt; 1./FPS):
    prev_time = time.time()

    resized_frame = cv2.resize(frame, (640, 640))
    results = model.predict(resized_frame, show = True)

  if cv2.waitley(1) == ord('q'):
    break

cap.release()
cv2.destroyAllWindows()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Geany 텍스트 에디터(.py 파일로 만들어야함)에 위 코드를 들고와서 코드를 실행을 한다면 카메라를 통해서 실시간으로 학습시킨 데이터에 맞춰 객체에 대해서 박스가 생기고, 박스가 탐지가 된다면 tkinter의 메세지박스가 출력이 되도록 만들어 주었다.&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;이렇게 Raspberry pi4와 카메라를 이용하여 실시간으로 화재를 감지할 수 있는 인공지능 카메라를 만들어보았다.&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;&lt;b&gt; 캡스톤 디자인 결과물 문제점 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Raspberry pi4의 모듈 성능으로 인하여, 실시간으로 카메라 탐지하기에는 속도가 느리다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 라벨링된 이미지의 퀄리티와 양이 적거나 좋지않기 때문에 모델을 만들어도 성능이 원하는 만큼이 나오질 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. YOLOv8 모델 학습을 하기위해 colab을 사용하였는데, colab에는 일정시간이 지나면 초기화가 되는 단점이 존재하여, 더욱 깊게 학습을 시키지 못하여서 모델 성능이 일정이상 올리기 힘들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 모델에 지정한 불이나 연기에 대한 바운딩박스가 출력되면 메세지박스가 출력되는데, 메세지 박스가 출력되면 메세지 박스 출력되는 기준으로 카메라의 작동이 멈춰 있어서 객체가 탐지가 되면 알림을 보내는 방식을 변경해야할 것 같다.&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;/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;&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;</description>
      <category>Deep Learning</category>
      <author>DataKwon</author>
      <guid isPermaLink="true">https://koy0911.tistory.com/4</guid>
      <comments>https://koy0911.tistory.com/4#entry4comment</comments>
      <pubDate>Wed, 20 Dec 2023 15:46:08 +0900</pubDate>
    </item>
    <item>
      <title>Daicon 경진대회 - 대구 교통사고 피해 예측 모델링 코드</title>
      <link>https://koy0911.tistory.com/3</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이전 글에서 대구 교통사고 피해 데이터에 대한 EDA 및 분석을 수행하였다.&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;먼저 필요할 것 같은 라이브러리를 불러온다.&lt;/p&gt;
&lt;pre id=&quot;code_1702363844728&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
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
encoding_type = 'euc-kr'
import warnings
warnings.filterwarnings('ignore')

#데이터셋
train_data = pd.read_csv('./dataset/accident/train.csv')
test_data = pd.read_csv('./dataset/accident/test.csv')
result_data = pd.read_csv('./dataset/accident/sample_submission.csv')
daegu_cctv_data = pd.read_csv('./dataset/accident/daegu_cctv.csv', encoding = encoding_type)
daegu_child_protect_data = pd.read_csv('./dataset/accident/daegu_child_p.csv', encoding = encoding_type)
daegu_lamp_data = pd.read_csv('./dataset/accident/daegu_lamp.csv', encoding = encoding_type)
daegu_parking_area_data = pd.read_csv('./dataset/accident/daegu_parking_area.csv', encoding = encoding_type)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 데이터셋을 불러왔다. 데이터 셋 중 대구 cctv데이터와 어린이보호구역 데이터, 보안등 데이터, 주차지역 데이터도 함께 사용하면 좋을 것 같아서 들고왔다. 이 cctv, 어린이 보호구역, 보안등, 주차지역 데이터는 한글을 사용하는 데이터 이기 때문에 한글을 표현하기 위해 인코딩 타입을 euc-kr을 사용해 들고왔다.&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;train데이터셋은 이전 EDA를 통해 어떤 변수가 있는지 확인했기 때문에 새로 들고온 데이터에 대해서 info()함수를 통해 무슨 데이터가 존재하는지 확인해본다.&lt;/p&gt;
&lt;pre id=&quot;code_1702364201132&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;print(daegu_cctv_data.info(), '\n\n')
print(daegu_child_protect_data.info())&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;414&quot; data-origin-height=&quot;666&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWguwT/btsBG3HFjCV/e3bk1jk1RGklDwp2YkqIy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWguwT/btsBG3HFjCV/e3bk1jk1RGklDwp2YkqIy0/img.png&quot; data-alt=&quot;대구 cctv, 어린이보호구역 데이터 종류&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWguwT/btsBG3HFjCV/e3bk1jk1RGklDwp2YkqIy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWguwT%2FbtsBG3HFjCV%2Fe3bk1jk1RGklDwp2YkqIy0%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;310&quot; height=&quot;499&quot; data-origin-width=&quot;414&quot; data-origin-height=&quot;666&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;대구 cctv, 어린이보호구역 데이터 종류&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1702364257073&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;print(daegu_lamp_data.info(), '\n\n')
print(daegu_parking_area_data.info())&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;350&quot; data-origin-height=&quot;757&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oFRrr/btsBSaSyNBD/N5zvDGd5tgf6gJYVyOJgEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oFRrr/btsBSaSyNBD/N5zvDGd5tgf6gJYVyOJgEK/img.png&quot; data-alt=&quot;대구 보안등, 주차구역 데이터 종류&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oFRrr/btsBSaSyNBD/N5zvDGd5tgf6gJYVyOJgEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoFRrr%2FbtsBSaSyNBD%2FN5zvDGd5tgf6gJYVyOJgEK%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;350&quot; height=&quot;757&quot; data-origin-width=&quot;350&quot; data-origin-height=&quot;757&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;대구 보안등, 주차구역 데이터 종류&lt;/figcaption&gt;
&lt;/figure&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;여기서 우리가 사용할 데이터를 고를 것이다. 보안등 데이터의 경우에는 소재지지번주소와 설치개수를 사용할 것이고, 어린이보호구역 데이터는 어디에 어린이보호구역이 있는지를 사용하기 위해 소재지지번주소를 사용하고, 주차구역 데이터는 주차구역이 어디에 속하는지에 대한 소재지지번주소와 급지구분을 사용할 것이다. cctv데이터를 사용하지 않은 이유는 마지막에 알려줄 것이다.&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;/p&gt;
&lt;pre id=&quot;code_1702364936860&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cols_lamp = ['설치개수', '소재지지번주소']
light_df = daegu_lamp_data[cols_lamp]
# 수행결과 소재지지번주소는 ~~광역시 ~~구 ~~동 1722-4 라는 형식으로 나온다.
#이러한 형식을 처리하기 위해 소재지지번주소를 4개인 시 구 동 번지로 나눌 수 있도록 한다.
location_pattern = r'(\S+) (\S+) (\S+) (\S+)'

#location_pattern을 통해 소재지지번주소를 도시 구 동 번지로 나눠준다.
light_df[['도시', '구', '동',' 번지']] = light_df['소재지지번주소'].str.extract(location_pattern)
#그 후 필요없는 소재지지번주소를 삭제해준다.
light_df = light_df.drop(columns = ['소재지지번주소'])
# 그다음 train데이터의 시군구에는 번지가 존재하지 않기 때문에 번지 또한 삭제해준다.
light_df = light_df.drop(columns = [' 번지'])&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;pre id=&quot;code_1702365050935&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;light_df = light_df.groupby(['도시', '구', '동']).sum().reset_index()
light_df.reset_index(inplace = True, drop = True)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 동 별로 보안등의 설치개수를 구할 수 있게 되었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;206&quot; data-origin-height=&quot;132&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xfW4v/btsBQTDvB3h/gijdTjm8aDbQw3mkKzGMX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xfW4v/btsBQTDvB3h/gijdTjm8aDbQw3mkKzGMX1/img.png&quot; data-alt=&quot;도시-구-동 별 보안등 설치개수&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xfW4v/btsBQTDvB3h/gijdTjm8aDbQw3mkKzGMX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxfW4v%2FbtsBQTDvB3h%2FgijdTjm8aDbQw3mkKzGMX1%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;206&quot; height=&quot;132&quot; data-origin-width=&quot;206&quot; data-origin-height=&quot;132&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;도시-구-동 별 보안등 설치개수&lt;/figcaption&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그다음은 어린이 보호구역의 위치에 대해서 데이터를 처리해보겠다.&lt;/p&gt;
&lt;pre id=&quot;code_1702365871804&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;col_protect = ['소재지지번주소']
#어린이 보호구역에 대한 소재지지번주소의 중복된 값을 삭제
child_protect_df = daegu_child_protect_data[col_protect].drop_duplicates()

# 새로운 열을 만들어 어린이보호구역 개수를 1을 넣어줌
child_protect_df['어린이보호구역 개수'] = 1

location_pattern = r'(\S+) (\S+) (\S+) (\S+)'
#어린이 보호구역의 소재지지번주소를 도시 구 동 번지로 분리해줌
child_protect_df[['도시', '구', '동', '번지']] = child_protect_df['소재지지번주소'].str.extract(location_pattern)
# 그중 소재지지번주소와 번지를 삭제해준다.
child_protect_df = child_protect_df.drop(columns = ['소재지지번주소', '번지'])

#그 후 도시, 구, 동을 기준으로 묶고 값을 값을 더해준다.
child_protect_df = child_protect_df.groupby(['도시', '구', '동']).sum().reset_index()

child_protect_df.reset_index(inplace = True, drop = True)

#결과확인
child_protect_df.head()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;264&quot; data-origin-height=&quot;138&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpcg9V/btsBHpjeZpR/E3WEVyIKiu8W08CuWt9ayK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpcg9V/btsBHpjeZpR/E3WEVyIKiu8W08CuWt9ayK/img.png&quot; data-alt=&quot;동 별 어린이보호구역 개수&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpcg9V/btsBHpjeZpR/E3WEVyIKiu8W08CuWt9ayK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbpcg9V%2FbtsBHpjeZpR%2FE3WEVyIKiu8W08CuWt9ayK%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;264&quot; height=&quot;138&quot; data-origin-width=&quot;264&quot; data-origin-height=&quot;138&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;동 별 어린이보호구역 개수&lt;/figcaption&gt;
&lt;/figure&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;그 다음으로 주차지역에 대한 데이터를 처리해보았다.&lt;/p&gt;
&lt;pre id=&quot;code_1702366052099&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 사용할 소재지지번주소와 급지구분을 들고온다.
col_parking = ['소재지지번주소', '급지구분']
parking_df = daegu_parking_area_data[col_parking]

location_pattern = r'(\S+) (\S+) (\S+) (\S+)'

parking_df[['도시', '구', '동', '번지']] = parking_df['소재지지번주소'].str.extract(location_pattern)

#소재지지번주소와 번지 삭제
parking_df = parking_df.drop(columns = ['소재지지번주소', '번지'])

#도시 구 동 기준으로 데이터의 합을 구함
parking_df = parking_df.groupby(['도시', '구', '동']).sum().reset_index()
parking_df.reset_index(inplace = True, drop = True)

#데이터 확인
parking_df.head()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;207&quot; data-origin-height=&quot;138&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmg5R4/btsBMVvaWAN/YKMp6oaIzXVcPG0qIwo1Q1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmg5R4/btsBMVvaWAN/YKMp6oaIzXVcPG0qIwo1Q1/img.png&quot; data-alt=&quot;주차지역에 따른 급지구분 합&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmg5R4/btsBMVvaWAN/YKMp6oaIzXVcPG0qIwo1Q1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdmg5R4%2FbtsBMVvaWAN%2FYKMp6oaIzXVcPG0qIwo1Q1%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;207&quot; height=&quot;138&quot; data-origin-width=&quot;207&quot; data-origin-height=&quot;138&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;주차지역에 따른 급지구분 합&lt;/figcaption&gt;
&lt;/figure&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;이제 train, test데이터에 대한 전처리를 수행한다.&lt;/p&gt;
&lt;pre id=&quot;code_1702366313620&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import datetime as dt
#사고일시를 datetime형식으로 변환
train_org['사고일시'] = pd.to_datetime(train_org['사고일시'])
test_org['사고일시'] = pd.to_datetime(test_org['사고일시'])

#변환한 데이터에서 사고일시를 년 월 일 시로 분리해서 새로운 열에 넣음
train_org['년'] = train_org['사고일시'].dt.year
train_org['월'] = train_org['사고일시'].dt.month
train_org['일'] = train_org['사고일시'].dt.day
train_org['시'] = train_org['사고일시'].dt.hour

test_org['년'] = test_org['사고일시'].dt.year
test_org['월'] = test_org['사고일시'].dt.month
test_org['일'] = test_org['사고일시'].dt.day
test_org['시'] = test_org['사고일시'].dt.hour

# 그 후 사고일시라는 데이터를 삭제함
train_org = train_org.drop(columns = ['사고일시'])
test_org = test_org.drop(columns = ['사고일시'])

# train, test데이터의 시군구 데이터도 분리한다.
location_pattern_3 = r'(\S+) (\S+) (\S+)'
train_org[['도시', '구', '동']] = train_org['시군구'].str.extract(location_pattern_3)
test_org[['도시', '구', '동']] = test_org['시군구'].str.extract(location_pattern_3)

# 그 후 시군구라는 열의 값을 삭제한다.
train_org = train_org.drop(columns = ['시군구'])
test_org = test_org.drop(columns= ['시군구'])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 train, test데이터에서의 사고일시와 시군구를 분리하여 새로운 열의 데이터로 만들어준다.&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;/p&gt;
&lt;pre id=&quot;code_1702366456440&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;train_org['도로형태'].head()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;185&quot; data-origin-height=&quot;90&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVlZRz/btsBG6EoGRq/vDQkds74TlK0bYLpbzrUs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVlZRz/btsBG6EoGRq/vDQkds74TlK0bYLpbzrUs1/img.png&quot; data-alt=&quot;도로형태의 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVlZRz/btsBG6EoGRq/vDQkds74TlK0bYLpbzrUs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVlZRz%2FbtsBG6EoGRq%2FvDQkds74TlK0bYLpbzrUs1%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;185&quot; height=&quot;90&quot; data-origin-width=&quot;185&quot; data-origin-height=&quot;90&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;도로형태의 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 또한 데이터를 처리해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1702366533381&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#도로형태를 분리해준다.
road_pattern = r'(.+) - (.+)'
train_org[['도로형태1', '도로형태2']] = train_org['도로형태'].str.extract(road_pattern)
test_org[['도로형태1', '도로형태2']] = test_org['도로형태'].str.extract(road_pattern)

#기존의 도로형태를 삭제해준다.
train_org = train_org.drop(columns = ['도로형태'])
test_org = test_org.drop(columns = ['도로형태'])&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;/p&gt;
&lt;pre id=&quot;code_1702366723646&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 도시, 구, 동에 맞게 데이터를 합쳐준다.
train_org = pd.merge(train_org, light_df, how='left', on=['도시', '구', '동'])
train_org = pd.merge(train_org, child_protect_df, how='left', on=['도시', '구', '동'])
train_org = pd.merge(train_org, parking_df, how='left', on=['도시', '구', '동'])

test_org = pd.merge(test_org, light_df, how='left', on = ['도시', '구', '동'])
test_org = pd.merge(test_org, child_protect_df, how='left', on = ['도시', '구', '동'])
test_org = pd.merge(test_org, parking_df, how='left', on = ['도시', '구', '동'])

# 데이터 info() 결과
print(train_org.info(), '\n\n')
print(test_org.info())&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;306&quot; data-origin-height=&quot;776&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Z5Cdi/btsBUA4iAgd/RL1XtGXrwplvYrglZxv8Ek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Z5Cdi/btsBUA4iAgd/RL1XtGXrwplvYrglZxv8Ek/img.png&quot; data-alt=&quot;데이터 합친 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Z5Cdi/btsBUA4iAgd/RL1XtGXrwplvYrglZxv8Ek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZ5Cdi%2FbtsBUA4iAgd%2FRL1XtGXrwplvYrglZxv8Ek%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;306&quot; height=&quot;776&quot; data-origin-width=&quot;306&quot; data-origin-height=&quot;776&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;데이터 합친 결과&lt;/figcaption&gt;
&lt;/figure&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;이제 모델을 학습하기전에 train데이터와 test데이터와 곂치지 않는 데이터는 삭제를 해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1702366964181&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;test_x = test_org.drop(columns=['ID']).copy()
train_x = train_org.drop(columns=['ID', '사고유형 - 세부분류', '가해운전자 차종','가해운전자 성별','가해운전자 연령','가해운전자 상해정도', '피해운전자 차종', '피해운전자 성별', '피해운전자 연령', '피해운전자 상해정도', '법규위반', 'ECLO']).copy()
train_y = train_org['ECLO'].copy()&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 범주형 변수에 대해서 전처리를 수행할 것이며, 사용할 방법은 타겟인코더이다.&lt;/p&gt;
&lt;pre id=&quot;code_1702367411222&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 만약 타겟 인코더가 안불러와진다면 -&amp;gt; pip install category_encoders
from category_encoders.target_encoder import TargetEncoder
# 범주형 변수를 리스트형태로 들고온다
categorical_features = train_x.select_dtypes(include='object').columns.tolist()
#리스트형태로 범주형 변수가 잘 불러와졌는지 확인
display(categorical_features)

# target_encoder를 사용해 범주형 변수 인코딩 할 때 해당 변수의 값이 특정 타겟변수에 대한
# 평균값으로 인코딩을 수행하기 때문에 타겟변수를 같이 넣어준다.
for i in categorical_features:
    te = TargetEncoder(cols=[i])
    train_x[i] = te.fit_transform(train_x[i], train_y)
    test_x[i] = te.transform(test_x[i])

# 범주형 변수를 타겟 인코더로 변환한 값 확인
display(train_x.head())
display(test_x.head())&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;train_x값과 test_x 값을 다시 확인해보니 사망자수, 중상자수, 경상자수, 부상자수를 삭제하지 않은 것이 보였다. 이를 삭제해준다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;429&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kRhhy/btsBR7O8kIA/7T2ObpSjkyxwqPUqZuIDFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kRhhy/btsBR7O8kIA/7T2ObpSjkyxwqPUqZuIDFk/img.png&quot; data-alt=&quot;타겟 인코더로 스케일링한 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kRhhy/btsBR7O8kIA/7T2ObpSjkyxwqPUqZuIDFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkRhhy%2FbtsBR7O8kIA%2F7T2ObpSjkyxwqPUqZuIDFk%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;560&quot; height=&quot;429&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;429&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;타겟 인코더로 스케일링한 결과&lt;/figcaption&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;그리고 데이터 내에 결측값이 존재하는 곳이 있기 때문에 결측값에 0을 넣어서 채워준다.&lt;/p&gt;
&lt;pre id=&quot;code_1702367639154&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#train, test와 데이터가 맞게 삭제해준다.
train_x = train_x.drop(columns = ['사망자수', '중상자수', '경상자수', '부상자수', 'ECLO'])

# 결측값이 존재하는 곳에 0의값을 채워넣음
train_x.fillna(0, inplace = True)
test_x.fillna(0, inplace = True)&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;수치형 데이터에 대해서는 따로 손봐줄 것이 없어보이기 때문에 처리를 하지않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 데이터가 범주형 object 타입이며, 수치형이더라도 전부 년 월 일 시와 같은 데이터였기 때문이다.&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;모델 학습을 위한 train, test 분리를 수행한다.&lt;/p&gt;
&lt;pre id=&quot;code_1702368213942&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(train_x, train_y, test_size = 0.2, random_state=42)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 분리 한 후 RandomForestRegressor를 수행해보도록 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1702368343478&quot; class=&quot;python&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;from sklearn.ensemble import RandomForestRegressor
rfr = RandomForestRegressor(n_estimators = 100, random_state = 42)

#랜덤포레스트회귀 모델 생성
rfr.fit(x_train, y_train)

# 평가 기준인 rmsle 점수를 구하기 위한 분리한 x_test의 예측값을 구해준다.
y_pred_rfr = rfr.predict(x_test)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1702368460371&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.metrics import mean_squared_log_error

# rmsle 값
rmsle_result = np.sqrt(mean_squared_log_error(y_test, y_pred_rfr))

print(rmsle_result)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 값을 구하니 rmsle값이 0.48541 이 나오게 되었다.&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;이제 모델을 통해 직접 test_data에 맞는 예측값을 구해본다.&lt;/p&gt;
&lt;pre id=&quot;code_1702368656823&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# test_x에 모델을 적용시켜 예측값을 구함
y_predictions = rfr.predict(test_x)
y_predictions

#모델의 예측 결과값을 넣어야하는 파일을 복사후 값을 넣어준다.
result_data1 = result_data.copy()
result_data1['ECLO'] = y_prediction
#결과값
result_data1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;196&quot; data-origin-height=&quot;291&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lj4YE/btsBG5r11xS/mTsgygSnLoND7k0EZAH3qK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lj4YE/btsBG5r11xS/mTsgygSnLoND7k0EZAH3qK/img.png&quot; data-alt=&quot;예측 결과값&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lj4YE/btsBG5r11xS/mTsgygSnLoND7k0EZAH3qK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flj4YE%2FbtsBG5r11xS%2FmTsgygSnLoND7k0EZAH3qK%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;196&quot; height=&quot;291&quot; data-origin-width=&quot;196&quot; data-origin-height=&quot;291&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;예측 결과값&lt;/figcaption&gt;
&lt;/figure&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;이제 이러한 결과값을 저장한다.&lt;/p&gt;
&lt;pre id=&quot;code_1702368721247&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;result_data1.to_csv('./dataset/resultdata/rfr_model.csv', index = False)&lt;/code&gt;&lt;/pre&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;*cctv 데이터를 사용하지 않은 이유는 cctv 데이터의 소재지지번주소에는 test데이터셋에 존재하지 않는 지번주소가 존재했기 때문에 모델이 학습 및 예측이 되지 않았기 때문에 사용하지 않았다.&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;이 방법외에도 많은 방법이 존재하므로 많은 방법을 사용하여 좋은 성능을 내는 모델을 만들어내면 된다.&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;/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;Private Score기준: 942명 중 202등 (상위 21%) 를 얻게 되었다.&lt;/p&gt;</description>
      <category>데이터 모델링</category>
      <author>DataKwon</author>
      <guid isPermaLink="true">https://koy0911.tistory.com/3</guid>
      <comments>https://koy0911.tistory.com/3#entry3comment</comments>
      <pubDate>Tue, 12 Dec 2023 17:16:55 +0900</pubDate>
    </item>
    <item>
      <title>Daicon 경진대회 - 대구 교통사고 피해 예측 EDA 코드</title>
      <link>https://koy0911.tistory.com/2</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;대구 교통사고 피해예측 AI 경진대회가 있어서 참여를 해 보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(데이터 출처: &lt;a href=&quot;https://dacon.io/competitions/official/236193/data&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dacon.io/competitions/official/236193/data&lt;/a&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;코딩을 입력한 곳은 Jupyter Notebook을 사용하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1702351303257&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
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import os
import warnings
warnings.filterwarnings('ignore')
from matplotlib import rc
rc('font', family = 'Malgun Gothic')
plt.rcParams['axes.unicode_minus']= False&lt;/code&gt;&lt;/pre&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;pre id=&quot;code_1702351474692&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;train_data = pd.read_csv('./dataset/accident/train.csv')
test_data = pd.read_csv('./dataset/accident/test.csv')
result_data = pd.read_csv('./dataset/accident/sample_submission.csv')

print(train_data.info(), '\n')
print(test_data.info())&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 주피터 노트북에 사용할 데이터를 불러온 후 train데이터셋과 test데이터셋의 변수에 대한 정보를 불러와 무슨 변수들이 존재하는지에 대해서 info()함수를 통해 확인해보았다.&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 alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;376&quot; data-origin-height=&quot;752&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/03WQ7/btsBQrmyLOQ/d5nf2von31NU5DaaOx8EU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/03WQ7/btsBQrmyLOQ/d5nf2von31NU5DaaOx8EU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/03WQ7/btsBQrmyLOQ/d5nf2von31NU5DaaOx8EU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F03WQ7%2FbtsBQrmyLOQ%2Fd5nf2von31NU5DaaOx8EU0%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;300&quot; height=&quot;600&quot; data-origin-width=&quot;376&quot; data-origin-height=&quot;752&quot;/&gt;&lt;/span&gt;&lt;/figure&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;pre id=&quot;code_1702351727941&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# train, test 데이터셋중 ID는 데이터EDA를 할 때 사용하기 어려운 고유변수이기 때문에 제거해준다.
train_data.drop(['ID'], axis = 1, inplace = True)
test_data.drop(['ID'], axis = 1, inplace = True)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1702351900548&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 데이터에 대한 shape, 결측값 유무, 중복값, describe 통계값, 유니크 값의 개수를 알아보는 함수 생성
def wrangling(train_set, test_set):
    print('---'*10)
    display(train_set.shape)
    display(test_set.shape)
    print('---'*10)
    display(train_set.isna().sum())
    display(test_set.isna().sum())
    print('---'*10)
    display(train_set[train_set.duplicated()])
    display(test_set[test_set.duplicated()])
    print('---'*10)
    display(train_set.describe())
    display(test_set.describe())
    print('---'*10)
    display(train_set.nunique())
    display(test_set.nunique())
    
# train, test데이터를 넣어서 생성한 함수에 대한 값 출력
wrangling(train_data, test_data)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1702352389759&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 데이터에 대해서 int형식으로 변경하지만 만약 값이 결측값이면 nan값을 넣어준다.
import re
def extract_convert_int(data):
    numbers = re.findall(r'\d+', str(data))
    return int(numbers[0]) if numbers else np.nan
  
'''
가해운전자 연령과 피해운전자 연령은 연령이라는 수치형으로 나와야하는데 info()결과에서 object로
나왔기 때문에 int값으로 변환시켜준다.
값 중 결측값이면 nan값을 넣어주는 이유는 피해운전자 연령에서 결측값이 존재하기 때문이다.
'''
train_data['가해운전자 연령'] = train_data['가해운전자 연령'].apply(extract_convert_int)
train_data['피해운전자 연령'] = train_data['피해운전자 연령'].apply(extract_convert_int)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1702352588917&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'''
이렇게 처리한 데이터의 타입을 범주형인 object타입과 수치형인 int, object타입의 열의 종류를
구분하여 데이터의 타입에 따라 그래프를 그려볼 것이다.
'''
num_cols = train_data.select_dtypes(exclude = 'object').columns.tolist() #수치형 변수 열 추출
cat_cols = train_data.select_dtypes(include = 'object').columns.tolist() #범주형 변수 열 추출


# 수치형 변수에 대한 히스토그램을 그린다.
i = 0
plt.figure(figsize=(12, 8))
for col in num_cols:
    i += 1
    plt.subplot(3, 3, i)
    sns.distplot(train_data[col])
plt.tight_layout()&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;559&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cG1UaZ/btsBTZQr1LS/6jhsiyhundIatL0Y3R4tW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cG1UaZ/btsBTZQr1LS/6jhsiyhundIatL0Y3R4tW0/img.png&quot; data-alt=&quot;수치형 변수에 대한 히스토그램&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cG1UaZ/btsBTZQr1LS/6jhsiyhundIatL0Y3R4tW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcG1UaZ%2FbtsBTZQr1LS%2F6jhsiyhundIatL0Y3R4tW0%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;559&quot; height=&quot;366&quot; data-origin-width=&quot;559&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;수치형 변수에 대한 히스토그램&lt;/figcaption&gt;
&lt;/figure&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;더욱 확실하게 정규분포를 따르는지 확인해보기 위해 Q-Q Plot을 한번 찍어본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1702353054352&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from scipy import stats

i = 0
plt.figure(figsize=(12, 8))
for col in num_cols:
    i += 1
    plt.subplot(3, 3, i)
    stats.probplot(train_data[col], dist=&quot;norm&quot;, plot=plt)
    #sns.distplot(train_data[col])
plt.tight_layout()&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;545&quot; data-origin-height=&quot;358&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sWPeg/btsBGGFsFRm/seDK43yUX6eWHu0dB3cpDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sWPeg/btsBGGFsFRm/seDK43yUX6eWHu0dB3cpDK/img.png&quot; data-alt=&quot;수치형 데이터에 대한 Q-Q Plot&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sWPeg/btsBGGFsFRm/seDK43yUX6eWHu0dB3cpDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsWPeg%2FbtsBGGFsFRm%2FseDK43yUX6eWHu0dB3cpDK%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;545&quot; height=&quot;358&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;358&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;수치형 데이터에 대한 Q-Q Plot&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Q-Q Plot을 그려본 결과 가해운전자 연령, 피해운전자 연령은 확실하게 정규분포를 따른다고 할 수 있고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사망자수, 경상자수, 부상자수, ECLO의 Q-Q Plot은 잘 이어지다 선에 벗어나는 것을 보니 &lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;비정규적인 꼬리 부분이나 이상치의 존재가 있다는 것을 나타낸다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&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;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;이제 범주형 변수에 대해서 막대그래프를 그려 범주별로 비교를 해볼 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1702353357155&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;i = 0
plt.figure(figsize = (24, 24))
for col in ['요일',
           '기상상태',
           '시군구',
           '도로형태',
           '노면상태',
           '사고유형',
           '사고유형 - 세부분류',
            '법규위반',
            '가해운전자 차종',
            '가해운전자 성별',
            '가해운전자 상해정도',
            '피해운전자 차종',
            '피해운전자 성별',
            '피해운전자 상해정도'
           ]:
    
    i += 1
    plt.subplot(5, 3, i)
    sns.barplot(x=train_data[col], y= train_data['ECLO'], ci = None)
    plt.xticks(rotation=45)
plt.tight_layout()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 사용할 범주를 지정을 해 준 다음 이러한 범주 별 ECLO를 비교를 할 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;556&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dKhTSr/btsBQiQKrJf/DSfKdASTUnfPjOddkuzUAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dKhTSr/btsBQiQKrJf/DSfKdASTUnfPjOddkuzUAK/img.png&quot; data-alt=&quot;범주형 변수 별 막대그래프&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dKhTSr/btsBQiQKrJf/DSfKdASTUnfPjOddkuzUAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdKhTSr%2FbtsBQiQKrJf%2FDSfKdASTUnfPjOddkuzUAK%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;649&quot; height=&quot;661&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;556&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;범주형 변수 별 막대그래프&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;범주형 변수 별 ECLO에 대한 막대그래프로 알 수 있는 정보&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;- 토요일, 일요일의 경우에 ECLO가 다른 날짜보다 약간 높음&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;- 안개가 낀 상황에 ECLO가 높음&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;- 단일로 - 터널의 경우 ECLO가 높음&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;- 노면상태가 침수인 경우 ECLO가 높았으며 반대로, 적설인 경우 ECLO가 낮음&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;- 차vs사람 보다 차vs차일 때 ECLO가 높음&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;- 도로외이탈 - 추락일때가 ECLO가 가장 높고 그다음은 전도전복 - 전복, 추돌과 정면충돌이 비슷하게 높음&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;- 법규위반이 과속인 경우 ECLO가 높음&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;- 가해운전자 차종이 승용, 승합, 화물, 건설기계인 경우 ECLO가 높음&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;- 가해운전자 성별에 따른 차이는 보이지 않음&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;- 피해운전자 차종이 농기계인 경우 ECLO가 높음&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;그래프중 가해운전자 상해정도와 피해운전자의 상해정도를 보지않은 이유는 ECLO는 인명피해 심각도로&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;ECLO = 사망자수 * 10 + 중상자수 * 5 + 경상자수 * 3 + 부상자수 * 1 이렇게 구해지기 때문에 넣지 않았다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 중 시군구 별 ECLO의 막대그래프가 보기 힘들기 때문에 따로 확인해본다.&lt;/p&gt;
&lt;pre id=&quot;code_1702353678103&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;plt.figure(figsize=(50,12))
sns.barplot(x=train_data['시군구'], y= train_data['ECLO'], ci = None)
plt.xticks(rotation=90)
plt.show()&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;551&quot; data-origin-height=&quot;166&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rER5m/btsBG5kJN7q/rX21A52PHNfzWp5bqaHNi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rER5m/btsBG5kJN7q/rX21A52PHNfzWp5bqaHNi0/img.png&quot; data-alt=&quot;시군구 별 ECLO의 막대그래프&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rER5m/btsBG5kJN7q/rX21A52PHNfzWp5bqaHNi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrER5m%2FbtsBG5kJN7q%2FrX21A52PHNfzWp5bqaHNi0%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;551&quot; height=&quot;166&quot; data-origin-width=&quot;551&quot; data-origin-height=&quot;166&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;시군구 별 ECLO의 막대그래프&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 확인해봐도 보기 힘들지만 여기서 알 수 있는 것은 대구의 시군구 별 ECLO가 큰 차이는 없지만 특정 몇 구역에는 차이가 존재하는 것을 확인할 수 있다. 아마도 ECLO가 다른 시군구보다 큰 지역은 사고와 관련된 문제가 존재하는 것 같다&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;시군구별 ECLO평균이 높은곳과 낮은곳을 찾아볼 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1702354441277&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;num_by_region = train_data.groupby(['시군구'])['ECLO'].mean().sort_values(ascending=False)
print('높은 ECLO')
display(num_by_region[:10])
print('-'*50)
print('낮은 ECLO')
display(num_by_region[-10:])&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;369&quot; data-origin-height=&quot;463&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/esZzkf/btsBT02THwb/97KLY87P1BnHL6vcuNwvM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/esZzkf/btsBT02THwb/97KLY87P1BnHL6vcuNwvM1/img.png&quot; data-alt=&quot;ECLO 높은 지역과 낮은 지역의 각 평균&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/esZzkf/btsBT02THwb/97KLY87P1BnHL6vcuNwvM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FesZzkf%2FbtsBT02THwb%2F97KLY87P1BnHL6vcuNwvM1%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;369&quot; height=&quot;463&quot; data-origin-width=&quot;369&quot; data-origin-height=&quot;463&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ECLO 높은 지역과 낮은 지역의 각 평균&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;높은 ECLO와 낮은 ECLO의 시군구 지역을 확인할 수 있었고, ECLO가 높은 지역에 대해서 한번 직접적으로 무엇이 문제인 것인지 확인이 필요해 보인다.&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;위의 지역별 ECLO는 동을 기준으로 얻어진 ECLO의 평균값이기 때문에 군, 구에 대해서도 ECLO의 평균값을 구하여 군, 구로 ECLO의 평균을 한번 파악해본다.&lt;/p&gt;
&lt;pre id=&quot;code_1702355084137&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 데이터의 형태가 (시) (군/구) (동) 으로 이루어져 있기 때문에 이를 기준으로 분리해줄 수 있도록함
location_pattern = r'(\S+) (\S+) (\S+)'

# 도시 구 동이라는 컬럼을 만들어, 시를 train데이터의 도시에
# 군/구를 train데이터의 구에, 동을 train데이터의 동에 넣어준다.
train_data[['도시', '구', '동']] = train_data['시군구'].str.extract(location_pattern)

#train데이터를 구를 기준으로 그룹핑을 하여 ECLO의 평균 중 가장 큰 값 10개를 출력
display(train_data.groupby(['구'])['ECLO'].mean().nlargest(10))
#train데이터를 동을 기준으로 그룹핑을 하여 ECLO의 평균 중 가장 큰 값 10개를 출력
display(train_data.groupby(['동'])['ECLO'].mean().nlargest(10))&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;234&quot; data-origin-height=&quot;362&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ek6wKL/btsBQjvpwmt/VNjKb8FjPWRw4xM0ftE6JK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ek6wKL/btsBQjvpwmt/VNjKb8FjPWRw4xM0ftE6JK/img.png&quot; data-alt=&quot;구, 동을 기준으로 ECLO평균이 높은&amp;amp;amp;nbsp; &amp;amp;amp;nbsp; 10개의 값 출력&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ek6wKL/btsBQjvpwmt/VNjKb8FjPWRw4xM0ftE6JK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fek6wKL%2FbtsBQjvpwmt%2FVNjKb8FjPWRw4xM0ftE6JK%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;234&quot; height=&quot;362&quot; data-origin-width=&quot;234&quot; data-origin-height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;구, 동을 기준으로 ECLO평균이 높은&amp;amp;nbsp; &amp;amp;nbsp; 10개의 값 출력&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통하여 구를 기준으로 달성군이 ECLO평균이 가장 높고, 동을 기준으로 노곡동이 ECLO 평균이 가장 높은 것을&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;이번에는 법규위반 별 가해운전자 연령과 피해운전자의 연령의 boxplot을 그려보았다.&lt;/p&gt;
&lt;pre id=&quot;code_1702356173826&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;i = 0
plt.figure(figsize = (8, 10))
for col in ['가해운전자 연령',
            '피해운전자 연령'
           ]:
    
    i += 1
    plt.subplot(2, 1, i)
    sns.boxplot(data=train_data, y='법규위반', x = col)
plt.tight_layout()&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;540&quot; data-origin-height=&quot;670&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PcGcs/btsBKg7iQwO/ieAIlkUCUCVMsSsKxNYnh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PcGcs/btsBKg7iQwO/ieAIlkUCUCVMsSsKxNYnh1/img.png&quot; data-alt=&quot;법규위반별 가해, 피해운전자 연령의 boxplot&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PcGcs/btsBKg7iQwO/ieAIlkUCUCVMsSsKxNYnh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPcGcs%2FbtsBKg7iQwO%2FieAIlkUCUCVMsSsKxNYnh1%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;540&quot; height=&quot;670&quot; data-origin-width=&quot;540&quot; data-origin-height=&quot;670&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;법규위반별 가해, 피해운전자 연령의 boxplot&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;boxplot으로 알수 있었던 것은 법규위반별 가해, 피해운전자의 연령의 분포가 30~ 50대가 큰 것을 알 수 있다.&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;이번에는 가해운전자 연령과 피해운전자 연령과 ECLO에 대해서 산점도를 그려 무슨 관계를 가지고 있는지 확인을 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1702356426548&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;plt.scatter(x=train_data['가해운전자 연령'], y = train_data['ECLO'])
plt.ylabel('ECLO')

plt.scatter(x=train_data['피해운전자 연령'], y = train_data['ECLO'])
plt.ylabel('ECLO')
plt.legend(['가해운전자', '피해운전자'])&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;516&quot; data-origin-height=&quot;364&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k6gex/btsBQvpfXOz/KkuwgFXbshY3MBGIzzpUoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k6gex/btsBQvpfXOz/KkuwgFXbshY3MBGIzzpUoK/img.png&quot; data-alt=&quot;가해, 피해운전자 연령 - ECLO의 산점도&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k6gex/btsBQvpfXOz/KkuwgFXbshY3MBGIzzpUoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk6gex%2FbtsBQvpfXOz%2FKkuwgFXbshY3MBGIzzpUoK%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;516&quot; height=&quot;364&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;364&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;가해, 피해운전자 연령 - ECLO의 산점도&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;산점도 결과 가해운전자와 피해운전자의 연령은 ECLO와 선형관계가 존재하지 않는다는 것을 알 수 있다.&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;그 다음으로는 년, 월, 시간에 대해서 ECLO가 어떻게 되는지에 대해서 확인해본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 데이터 중 년, 월, 일, 시의 정보가 모두 들어있는 사고일시를 사용을 하여 데이터의 열을 제작하여 값을 넣어준다.&lt;/p&gt;
&lt;pre id=&quot;code_1702356843710&quot; class=&quot;prolog&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;import datetime as dt
train_data['사고일시'] = pd.to_datetime(train_data['사고일시'])

# 년도라는 열을 만들어 사고일시에서 년도의 값을 넣어준다.
train_data['년도'] = pd.to_datetime(train_data['사고일시']).dt.year

# 월이라는 열을 만들어 사고일시에서 월의 값을 넣어준다.
train_data['월'] = pd.to_datetime(train_data['사고일시']).dt.month

# 일이라는 열을 만들어 사고일시에서 일의 값을 넣어준다.
train_data['일'] = pd.to_datetime(train_data['사고일시']).dt.day

# 시간이라는 열을 만들어 사고일시에서 시간의 값을 넣어준다.
train_data['시간'] = pd.to_datetime(train_data['사고일시']).dt.hour&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;그 후 년도에 따른 ECLO의 그래프, 월에 대한 ECLO의 그래프, 시간에 대한 ECLO의 그래프를 그려준다.&lt;/p&gt;
&lt;pre id=&quot;code_1702356870631&quot; class=&quot;routeros&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;plt.figure(figsize=(18,12))
plt.subplot(3, 1, 1)
sns.lineplot(data=train_data, x= '년도', y = 'ECLO')

plt.subplot(3,1,2)
sns.barplot(data=train_data, x= '월', y = 'ECLO')

plt.subplot(3,1,3)
sns.lineplot(data=train_data, x = '시간', y='ECLO')&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;543&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vrfnG/btsBQi4ql2e/XYQo7lOXDAhx3AX7m8CSsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vrfnG/btsBQi4ql2e/XYQo7lOXDAhx3AX7m8CSsK/img.png&quot; data-alt=&quot;년, 월, 시에 따른 ECLO값 그래프&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vrfnG/btsBQi4ql2e/XYQo7lOXDAhx3AX7m8CSsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvrfnG%2FbtsBQi4ql2e%2FXYQo7lOXDAhx3AX7m8CSsK%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;543&quot; height=&quot;374&quot; data-origin-width=&quot;543&quot; data-origin-height=&quot;374&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;년, 월, 시에 따른 ECLO값 그래프&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그래프를 통해 ECLO의 값이 연도가 증가할수록 점진적으로 낮아지는 것을 알 수 있고, 월별에 따른 ECLO의 값에는 차이가 존재하지 않아 월은 상관이 없어보인다. 시간대에 따른 ECLO의 값에서는 20시부터 ECLO가 증가하기 시작하여 3시에 최고를 찍으며, 5시까지 높은 ECLO를 얻게 된다. 그 후의 시간대는 ECLO가 낮은 것을 알 수 있다.&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;/p&gt;
&lt;pre id=&quot;code_1702357281097&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 데이터 중 수치형 데이터를 구해준다.
numeric_data = train_data.select_dtypes(include=[np.number])
# 이렇게 구한 수치형 데이터에 대해서 상관계수를 구해준다.
correlation_matrix = numeric_data.corr()

# 구한 상관계수를 통해 히트맵을 그려준다.
plt.figure(figsize=(16,12))
sns.heatmap(correlation_matrix, annot = True)
plt.show()&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;548&quot; data-origin-height=&quot;457&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JeG8S/btsBHSr5MA8/s7tyx9TsPFpkbgor3nbb61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JeG8S/btsBHSr5MA8/s7tyx9TsPFpkbgor3nbb61/img.png&quot; data-alt=&quot;ㅇ수치형 데이터에 대한 상관계수 히트맵&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JeG8S/btsBHSr5MA8/s7tyx9TsPFpkbgor3nbb61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJeG8S%2FbtsBHSr5MA8%2Fs7tyx9TsPFpkbgor3nbb61%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;650&quot; height=&quot;542&quot; data-origin-width=&quot;548&quot; data-origin-height=&quot;457&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ㅇ수치형 데이터에 대한 상관계수 히트맵&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 히트맵에서 ECLO가 사망자수, 중상자수, 경상자수와 관계가 있다고 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 ECLO는 사망자수, 중상자수, 경상자수와 관계가 존재하는 이유는 ECLO자체가 사망자수, 중상자수, 경상자수, 부상자수를 기준으로 점수를 산정해서 만들어진 변수이기 때문이다.&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;이렇게 데이터 시각화를 통한 데이터 분석 및 EDA를 마치겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 부족한 실력이라서 다른 코드를 함께 참고하면서 만들었으며, 교통사고에 대한 도메인 지식이 따로 존재하지 않았기 때문에 무엇을 분석을 해야하는지 감이 잡히지 않아 다른사람이 EDA를 한 것을 다양하게 보며 시도를 해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부족한 부분이 있을 수 있지만 이는 차차 다른사람들의 코드를 하나씩 흡수해가면서 역량을 올리도록 할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음에 다른 프로젝트에 대해서 EDA 및 데이터분석을 조금이나마 더 숙달시켜 내것으로 만들기 위해 노력할 것이다.&lt;/p&gt;</description>
      <category>데이터 분석</category>
      <category>Daicon</category>
      <category>데이터 분석</category>
      <category>시각화</category>
      <author>DataKwon</author>
      <guid isPermaLink="true">https://koy0911.tistory.com/2</guid>
      <comments>https://koy0911.tistory.com/2#entry2comment</comments>
      <pubDate>Tue, 12 Dec 2023 14:13:09 +0900</pubDate>
    </item>
  </channel>
</rss>