반응형

오늘은 Manim을 활용한 시각화 애니메이션 예제를 몇 가지 알아보도록 하겠습니다.

Preview

Manim 설치는 아래의 포스팅을 확인해 주세요 :)

https://wonhwa.tistory.com/36?category=1001573

 

[python/시각화] Manim을 활용한 애니메이션 시각화(1) - 설치

안녕하세요! 오늘은 Manim을 활용하여 시각하하기 위한 설치를 진행해 보도록 하겠습니다. Preview Manim이란? Manim(mathematical animation engine)은 수학을 보다 쉽게 설명하고 학생들에게 가르치기 위해 개

wonhwa.tistory.com

 

예제1: 모양이 바뀌는 도형 만들기

첫 번째 예제는 도형을 하나 생성하여(2차원) 그 도형의 모양을 바꾸는 예제입니다.

저번 설치때 만든 manim 폴더에 start.py라는 파이썬 파일을 만들어 준 후, 아래와 같이 코드를 적어줍니다.

from manimlib import *

class SquareToCircle(Scene):
    def construct(self):
        #원 만들기
        circle = Circle()
        circle.set_fill(GREEN,opacity=1.0) #색은 바꿀 수 있음 #opacity는 투명도
        square = Square()
        self.play(ShowCreation(square))
        self.wait()
        #도형모양 변경부분(네모를 동그라미로)
        self.play(ReplacementTransform(square,circle))
        self.wait()
        # 원늘리기
        self.play(circle.animate.stretch(4, 0))
        #원 회전하기
        self.play(Rotate(circle, 90 * DEGREES))
        #도형 이동
        self.play(circle.animate.shift(2 * RIGHT).scale(0.25))
        #도형 굴곡
        circle.insert_n_curves(10)
        self.play(circle.animate.apply_complex_function(lambda z: z**2))
        #텍스트 입력하기
        text = Text("""
            Hello World! ^0^
        """)
        self.play(Write(text))
        always(circle.move_to, self.mouse_point)

        #애니메이션 종료 후 창을 닫고 싶을때
        #exit()

사각형과 네모 객체를 만든 후 네모를 원으로 바꾸고,

그 원의 모양을 또 바꾸어 마지막엔 텍스트를 추가하는 예제입니다.

이렇게 코드를 작성 후 저장해 주세요.

그 후 anaconda 프롬프트 창 또는 cmd 창을 열어 주세요.

#1. manim폴더 위치로 이동
cd manim 
#2. manim 가상환경 활성화
activate manim 
#또는 anaconda prompt 에서 동작 시
conda activate manim
#3. 함수 실행 명령어 입력
manimgl start.py SquareToCircle

#팁: 동영상으로 저장 시
manimgl start.py SquareToCircle -o

#팁2: 애니메이션 종료 시
#실행되고 있는 애니메이션 창 클릭 후
#q 키를 눌러 실행 종료

위의 명령어를 입력하면 작성한 코드가 실행이 됩니다.

실행 애니메이션을 저장할 수도 있습니다.

명령어 끝에 -o를 붙이면 videos 라는 폴더 안에 동영상이 저장됩니다.

화면 종료 시에는 실행되고 있는 애니메이션 창을 한번 클릭 후 q 키를 눌러 종료합니다.

 

예제2: 텍스트 애니메이션

다음으로 알아볼 예제는 텍스트 애니메이션입니다.

Manim에서는 텍스트로 애니메이션화할 때 특정 단어만 폰트 및 색상 변경이 가능합니다.

페이드인효과도 줄 수 있습니다.

class TextExample(Scene):
    def construct(self):
        text = Text("여기에 텍스트가 있습니다.", font="BM DoHyeon", font_size=90) #폰트 변경시 font= 에 원하는 폰트 이름 입력
        difference = Text(
            """
            Manim에서는 텍스트를 애니메이션으로 시각화가 가능합니다.\n
            지금 보고 계시는 폰트는 맑은 고딕인데요\n
            폰트 색도 단어마다 변경이 가능합니다.
            """,
            font="Malgun Gothic", font_size=24,
            # 단어마다 색 변경하기(딕셔너리)
            t2c={"텍스트": BLUE, "애니메이션": BLUE, "맑은 고딕": ORANGE}
        )
        VGroup(text, difference).arrange(DOWN, buff=1)
        self.play(Write(text))
        self.play(FadeIn(difference, UP)) #페이드인 효과
        self.wait(3)
        fonts = Text(
            "또한 폰트를 단어마다 다르게 설정할 수 있습니다.",
            font="Gulim",
            t2f={"폰트": "BM DoHyeon", "단어": "Malgun Gothic"}, #특정단어에 특정폰트 설정
            t2c={"폰트": BLUE, "단어": GREEN} #특정 단어에 색상 설정
        )
        fonts.set_width(FRAME_WIDTH - 1)
        slant = Text(
            "물론 이탤릭체와 굵기도 설정 가능합니다.",
            font="Malgun Gothic",
            t2s={"이탤릭체": ITALIC}, #텍스트 효과 주기
            t2w={"굵기": BOLD},
            t2c={"이탤릭체": ORANGE, "굵기": RED}
        )
        VGroup(fonts, slant).arrange(DOWN, buff=0.8)
        self.play(FadeOut(text), FadeOut(difference, shift=DOWN))
        self.play(Write(fonts))
        self.wait()
        self.play(Write(slant))
        self.wait()

한글을 작성할 때는 한글 폰트로 사용하여야 깨짐 현상이 일어나지 않습니다.

마찬가지로 명령창에 아래와 같은 명령어를 입력해주면 실행이 됩니다.

항상 start.py파일을 저장하고 실행해야 최신 상태로 구동이 됩니다.

# 코드실행
manimgl start.py TextExample

# 영상저장
manimgl start.py TextExample -o

#영상 종료 
q

 

 

예제3: 3차원 도형 및 이미지

마지막 예제로 3차원 도형을 시각화해보겠습니다.

지구 모양의 원을 만들고 이미지를 다운받아 표면을 표현해 줍니다.

그 후 회전을 주어 지구가 회전하는 모습을 보여줍니다.

또한 지구 낮 버전 밤 버전을 번갈아서 나타낼 수 있습니다.

아래의 코드를 입력해 주세요.

class SurfaceExample(Scene):
    CONFIG = {
        "camera_class": ThreeDCamera,
    }

    def construct(self):
        surface_text = Text(" 3차원으로 도형을 나타낼 수 있습니다.",font="BM DoHyeon")
        surface_text.fix_in_frame()
        surface_text.to_edge(UP)
        self.add(surface_text)
        self.wait(0.1)
        #원모양 도형 준비
        torus1 = Torus(r1=1, r2=1)
        torus2 = Torus(r1=3, r2=1)
        sphere = Sphere(radius=3, resolution=torus1.resolution)
        # 2가지 지구 버전 이미지 준비
        day_texture = "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Whole_world_-_land_and_oceans.jpg/1280px-Whole_world_-_land_and_oceans.jpg"
        night_texture = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/The_earth_at_night.jpg/1280px-The_earth_at_night.jpg"

        surfaces = [
            TexturedSurface(surface, day_texture, night_texture)
            for surface in [sphere, torus1, torus2]
        ]
        # 그리드(격자 보여주기)
        for mob in surfaces:
            mob.shift(IN)
            mob.mesh = SurfaceMesh(mob)
            mob.mesh.set_stroke(BLUE, 1, opacity=0.5)

        # Set perspective 특징설정
        frame = self.camera.frame
        frame.set_euler_angles(
            theta=-30 * DEGREES,
            phi=70 * DEGREES,
        )

        surface = surfaces[0]
        surface.save_state()
        self.play(
            FadeIn(surface),
            ShowCreation(surface.mesh, lag_ratio=0.01, run_time=3),
        )
        
        for mob in surfaces:
            mob.add(mob.mesh)
        surface.save_state()
        self.play(Rotate(surface, PI/2), run_time=2)
        for mob in surfaces[1:]:
            mob.rotate(PI/2)

        # 회전모션 추가
        frame.add_updater(lambda m, dt: m.increment_theta(-0.1 * dt))

        #밤의 지구버전 보여주기
        light_text = Text("2가지 사진을 사용하여 번갈아 가며 나타낼 수도 있습니다.",font="BM DoHyeon")
        light_text.move_to(surface_text)
        light_text.fix_in_frame()

        self.play(FadeTransform(surface_text, light_text))
        light = self.camera.light_source
        self.add(light)
        light.save_state()
        self.play(light.animate.move_to(3 * IN), run_time=5)
        self.play(light.animate.shift(10 * OUT), run_time=5)

        drag_text = Text("d나 s를 누른 상태에서 마우스를 움직여 물체를 이동시켜 보세요.",font="BM DoHyeon")
        drag_text.move_to(light_text)
        drag_text.fix_in_frame()

        self.play(FadeTransform(light_text, drag_text))
        self.wait()

이번에는 d나 s를 눌러 상호작용이 가능합니다.

d는 도형 내에서 원하는 각도로 변경할 수 있고 s는 도형 자체를 이동시킬 수 있습니다.

# 코드실행
manimgl start.py SurfaceExample

# 영상저장
manimgl start.py SurfaceExample -o

#종료
q

 

참고자료

- Manim 문서

https://3b1b.github.io/manim/getting_started/quickstart.html

 

Quick Start - manim documentation

Previous Installation

3b1b.github.io

 

전체코드
from manimlib import *

class SquareToCircle(Scene):
    def construct(self):
        #원 만들기
        circle = Circle()
        circle.set_fill(GREEN,opacity=1.0) #색은 바꿀 수 있음 #opacity는 투명도
        square = Square()
        self.play(ShowCreation(square))
        self.wait()
        #도형모양 변경부분(네모를 동그라미로)
        self.play(ReplacementTransform(square,circle))
        self.wait()
        # 원늘리기
        self.play(circle.animate.stretch(4, 0))
        #원 회전하기
        self.play(Rotate(circle, 90 * DEGREES))
        #도형 이동
        self.play(circle.animate.shift(2 * RIGHT).scale(0.25))
        #도형 굴곡
        circle.insert_n_curves(10)
        self.play(circle.animate.apply_complex_function(lambda z: z**2))
        #텍스트 입력하기
        text = Text("""
            Hello World! ^0^
        """)
        self.play(Write(text))
        always(circle.move_to, self.mouse_point)

        #애니메이션 종료 후 창을 닫고 싶을때
        #exit()


class TextExample(Scene):
    def construct(self):
        text = Text("여기에 텍스트가 있습니다.", font="BM DoHyeon", font_size=90) #폰트 변경시 font= 에 원하는 폰트 이름 입력
        difference = Text(
            """
            Manim에서는 텍스트를 애니메이션으로 시각화가 가능합니다.\n
            지금 보고 계시는 폰트는 맑은 고딕인데요\n
            폰트 색도 단어마다 변경이 가능합니다.
            """,
            font="Malgun Gothic", font_size=24,
            # 단어마다 색 변경하기(딕셔너리)
            t2c={"텍스트": BLUE, "애니메이션": BLUE, "맑은 고딕": ORANGE}
        )
        VGroup(text, difference).arrange(DOWN, buff=1)
        self.play(Write(text))
        self.play(FadeIn(difference, UP)) #페이드인 효과
        self.wait(3)
        fonts = Text(
            "또한 폰트를 단어마다 다르게 설정할 수 있습니다.",
            font="Gulim",
            t2f={"폰트": "BM DoHyeon", "단어": "Malgun Gothic"}, #특정단어에 특정폰트 설정
            t2c={"폰트": BLUE, "단어": GREEN} #특정 단어에 색상 설정
        )
        fonts.set_width(FRAME_WIDTH - 1)
        slant = Text(
            "물론 이탤릭체와 굵기도 설정 가능합니다.",
            font="Malgun Gothic",
            t2s={"이탤릭체": ITALIC}, #텍스트 효과 주기
            t2w={"굵기": BOLD},
            t2c={"이탤릭체": ORANGE, "굵기": RED}
        )
        VGroup(fonts, slant).arrange(DOWN, buff=0.8)
        self.play(FadeOut(text), FadeOut(difference, shift=DOWN))
        self.play(Write(fonts))
        self.wait()
        self.play(Write(slant))
        self.wait()

class SurfaceExample(Scene):
    CONFIG = {
        "camera_class": ThreeDCamera,
    }

    def construct(self):
        surface_text = Text(" 3차원으로 도형을 나타낼 수 있습니다.",font="BM DoHyeon")
        surface_text.fix_in_frame()
        surface_text.to_edge(UP)
        self.add(surface_text)
        self.wait(0.1)
        #원모양 도형 준비
        torus1 = Torus(r1=1, r2=1)
        torus2 = Torus(r1=3, r2=1)
        sphere = Sphere(radius=3, resolution=torus1.resolution)
        # 2가지 지구 버전 이미지 준비
        day_texture = "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Whole_world_-_land_and_oceans.jpg/1280px-Whole_world_-_land_and_oceans.jpg"
        night_texture = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/The_earth_at_night.jpg/1280px-The_earth_at_night.jpg"

        surfaces = [
            TexturedSurface(surface, day_texture, night_texture)
            for surface in [sphere, torus1, torus2]
        ]
        # 그리드(격자 보여주기)
        for mob in surfaces:
            mob.shift(IN)
            mob.mesh = SurfaceMesh(mob)
            mob.mesh.set_stroke(BLUE, 1, opacity=0.5)

        # Set perspective 특징설정
        frame = self.camera.frame
        frame.set_euler_angles(
            theta=-30 * DEGREES,
            phi=70 * DEGREES,
        )

        surface = surfaces[0]
        surface.save_state()
        self.play(
            FadeIn(surface),
            ShowCreation(surface.mesh, lag_ratio=0.01, run_time=3),
        )
        
        for mob in surfaces:
            mob.add(mob.mesh)
        surface.save_state()
        self.play(Rotate(surface, PI/2), run_time=2)
        for mob in surfaces[1:]:
            mob.rotate(PI/2)

        # 회전모션 추가
        frame.add_updater(lambda m, dt: m.increment_theta(-0.1 * dt))

        #밤의 지구버전 보여주기
        light_text = Text("2가지 사진을 사용하여 번갈아 가며 나타낼 수도 있습니다.",font="BM DoHyeon")
        light_text.move_to(surface_text)
        light_text.fix_in_frame()

        self.play(FadeTransform(surface_text, light_text))
        light = self.camera.light_source
        self.add(light)
        light.save_state()
        self.play(light.animate.move_to(3 * IN), run_time=5)
        self.play(light.animate.shift(10 * OUT), run_time=5)

        drag_text = Text("d나 s를 누른 상태에서 마우스를 움직여 물체를 이동시켜 보세요.",font="BM DoHyeon")
        drag_text.move_to(light_text)
        drag_text.fix_in_frame()

        self.play(FadeTransform(light_text, drag_text))
        self.wait()

 

터미널 명령어 모음
#1. manim폴더 위치로 이동
cd manim 
#2. manim 가상환경 활성화
activate manim 
#또는 anaconda prompt 에서 동작 시
conda activate manim
#3. 함수 실행 명령어 입력
manimgl start.py SquareToCircle

#팁: 동영상으로 저장 시
manimgl start.py SquareToCircle -o

#팁2: 애니메이션 종료 시
#실행되고 있는 애니메이션 창 클릭 후
#q 키를 눌러 실행 종료

# 예제2 코드실행
manimgl start.py TextExample

# 영상저장
manimgl start.py TextExample -o

#영상 종료 
q

# 예제3 코드실행
manimgl start.py SurfaceExample

# 영상저장
manimgl start.py SurfaceExample -o

#종료
q

 

코드 파일

start.py
0.01MB

마무리

오늘은 간단한 Manim 예제 몇가지를 알아보았습니다 ㅎㅎ

마님 문서에 가면 더 다양한 예제를 확인할 수 있습니다.

Manim을 활용하여 시각화하고 싶은 애니메이션이 있다면 댓글로 알려주세요 :)

저도 활용하기 좋은 아이디어가 있으면 포스팅으로 공유하도록 하겠습니다.ㅎㅎ

반응형
반응형

안녕하세요! 오늘은 Manim을 활용하여 시각하하기 위한 설치를 진행해 보도록 하겠습니다.

Preview

Manim이란?

Manim(mathematical animation engine)은 수학을 보다 쉽게 설명하고 학생들에게 가르치기 위해 개발이 되었습니다. 수학관련 공식 및 설명등을 애니메이션으로 시각화하여 나타내는 엔진입니다. Manim은 수학 공식뿐 아니라 다른 텍스트, 도형 등도 시각화할 수 있어 소개해 드리고자 합니다 :)

 

Manim 설치

Manim을 사용하기 위해서는 미리 설치해야 되는 프로그램들이 있습니다.

Windows기준으로 설치 방법을 안내해 드리겠습니다.

1. MikTex 설치
 

Getting MiKTeX

a. Register GPG key sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys D6BC243565B2087BC3F897C9277A7293F59E4889 b. Register installation source Ubuntu 20.04 LTS (Focal Fossa): echo "deb http://miktex.org/download/ubuntu focal universe"

miktex.org

All downloads에 들어가 본인 컴퓨터에 맞는 Net Installer를 다운받아 설치해 주세요.(관리자 권한으로 실행)

저는 windows Net Installer 64-bit를 설치하였습니다.

2. FFmpeg 설치

FFmpeg 설치는 아래의 링크를 참고하여 설치해 주세요:)

https://wonhwa.tistory.com/15?category=1001573

 

[python] bar-chart-race로 시각화하기 (feat. 축구)

안녕하세요! 오늘은 bar-chart-race(직역하면 막대그래프 경주)를 이용해서 시각화 하는 방법을 알려드리려고 합니다. 예제로 EPL 영국 프리미어 축구 리그 데이터를 활용하여 bar-chart-race 시각화를

wonhwa.tistory.com

위의 게시물에서 step2. FFmpeg 설치하기를 참고하면 됩니다 ㅎㅎ

3. Sox 설치
 

SoX - Sound eXchange

Download SoX - Sound eXchange for free. SoX is the Swiss Army Knife of sound processing utilities. It can convert audio files to other popular audio file types and also apply sound effects and filters during the conversion.

sourceforge.net

파일 다운로드 후 설치를 진행해 주세요.(관리자 권한으로 실행)

위의 3번까지의 과정은 youtube에서도 확인할 수 있습니다.

아래의 영상을 참고해 주세요.

https://www.youtube.com/watch?v=ZltiKHFWmv8

4. pip3 install virtualenv(가상환경) 설치

그 후 터미널에서 위 명령어로 가상환경설정이 가능하도록 설치해줍니다.

5. pip install pycario 설치

4번과 마찬가지로 pycario도 설치해 줍니다.

6. manim 가상환경 설정

manim을 사용할 폴더를 하나 만들어 줍니다.

저는 C:Users\users 에 manim이라는 폴더를 만들어 주었습니다.

그후 cmd창을 열고,

1. cd C:\Users\user\tmanim
2. virtualenv manim
3. .\manim\Scripts\activate
4. activate manim

위의 명령어를 차례대로 입력해주면,

(manim) 파일경로 > 

이런 형태의 명령창이 나옵니다. 그럼 가상환경 설정은 끝났습니다.

7. manim 다운받기
pip install manimgl

위 명령어로 설치 후, 아래의 명령어를 추가로 설치해 manim 예시 파일을 열어보도록 합시다.

git clone https://github.com/3b1b/manim.git
cd manim
pip install -e .
manimgl example_scenes.py OpeningManimExample

 

위의 영상처럼 example이 잘 실행되면 manim 설치가 완료되었습니다 :)

참고자료

1. manim 깃헙  https://github.com/3b1b/manim

 

GitHub - 3b1b/manim: Animation engine for explanatory math videos

Animation engine for explanatory math videos. Contribute to 3b1b/manim development by creating an account on GitHub.

github.com

2. 관련 유튜브

https://www.youtube.com/channel/UCYO_jab_esuFRV4b17AJtAw

 

3Blue1Brown

3Blue1Brown, by Grant Sanderson, is some combination of math and entertainment, depending on your disposition. The goal is for explanations to be driven by animations and for difficult problems to be made simple with changes in perspective. For more inform

www.youtube.com

https://www.youtube.com/channel/UCxiWCEdx7aY88bSEUgLOC6A

 

Theorem of Beethoven

Welcome!!! ► About me: My name is Alexander, I'm a mechanic engineering student and I live in Mexico city. ► About the content of this channel: This channel is dedicated to the musical and scientific divulgation with explanatory animations. However, th

www.youtube.com

 

TO BE CONTINUED...

다음 시간에는 Manim으로 만들 수 있는 애니메이션 몇 가지를 소개해 보도록 하겠습니다 ㅎㅎ

반응형
반응형

이번에 할 자연어처리 포스팅은 감정분류입니다 :)

감정분류는 어떤 텍스트가 있을 때, 그 텍스트가 긍정인지, 부정인지 분류해 주는 것을 말합니다.

 

이번에 사용할 데이터는 감정분류 대표 예제인 네이버 영화 리뷰  데이터를 가지고

감정분류를 위한 전처리, 모델링, 학습, 예측까지 진행해 보도록 하겠습니다.

 

데이터 준비

https://github.com/e9t/nsmc

 

GitHub - e9t/nsmc: Naver sentiment movie corpus

Naver sentiment movie corpus. Contribute to e9t/nsmc development by creating an account on GitHub.

github.com

위의 링크에 들어가서 

1. ratings.txt - 전체 리뷰데이터(20만건)

2. ratings_train.txt - 학습데이터(15만건)

3. ratings_test.txt - 평가데이터(5만건)

위의 세 파일을 다운받아 주세요.

그 후 DATA 라는 폴더를 만들어 그 안에 파일들이 위치하도록 해줍니다.

 

데이터 분석하기

감정분류에 사용할 데이터가 어떻게 이루어져있는지 살펴보도록 하겠습니다.

어떤 데이터고 길이는 어느정도 되는지, 많이 나온 단어 수 등등을 분석하면서 추후 모델링에 대한 좋은 아이디어가 생길 수도 있기 때문입니다.

import numpy as np
import pandas as pd
import os
import matplotlib.pyplot as plt
import seaborn as sns
from wordcloud import WordCloud

DATA_PATH = '/content/sample_data/DATA/' #데이터경로 설정
print('파일 크기: ')
for file in os.listdir(DATA_PATH):
  if 'txt' in file:
    print(file.ljust(30)+str(round(os.path.getsize(DATA_PATH+ file) / 100000,2))+'MB')

파일 크기는 각각 위의 사진과 같습니다.

train은 전체 데이터의 75%, test는 25%정도 됩니다.

학습할 데이터를 확인해 보도록 하겠습니다.

#트레인 파일 불러오기
train_data = pd.read_csv(DATA_PATH + 'ratings_train.txt',header = 0, delimiter = '\t', quoting=3)
train_data.head()

train파일에서는 id, document(리뷰), label(긍정인지 부정인지) 이렇게 3가지 정보를 나타내는 컬럼이 있습니다.

print('학습데이터 전체 개수: {}'.format(len(train_data)))

학습데이터는 그전에 언급했듯이 15만건이 있습니다. 총 15만개의 행과 3개의 열로 이루어져 있습니다.

리뷰 길이들을 확인해 보겠습니다.

#리뷰 전체길이 확인
train_length = train_data['document'].astype(str).apply(len)
train_length.head()

앞에 5행만 대표적으로 출력했을 때 각각 리뷰의 길이는 위와 같습니다.

#리뷰 통계 정보
print('리뷰 길이 최댓값: {}'.format(np.max(train_length)))
print('리뷰 길이 최솟값: {}'.format(np.min(train_length)))
print('리뷰 길이 평균값: {:.2f}'.format(np.mean(train_length)))
print('리뷰 길이 표준편차: {:.2f}'.format(np.std(train_length)))
print('리뷰 길이 중간값: {}'.format(np.median(train_length)))
print('리뷰 길이 제1사분위: {}'.format(np.percentile(train_length,25)))
print('리뷰 길이 제3사분위: {}'.format(np.percentile(train_length,75)))

리뷰 길이에 대해 간단한 통계 분석을 해보았을 때, 리뷰는 평균적으로 35.24의 길이를 가집니다.

 

이번에는 리뷰에서 어떤 단어가 가장 많이 나오는지 빈도분석을 워드클라우드(wordcloud)로 해 보겠습니다.

워드클라우드를 만들기 위한 전처리로 str타입이 아닌 데이터를 모두 제거해 줍니다.

# 문자열 아닌 데이터 모두 제거
train_review = [review for review in train_data['document'] if type(review) is str]
train_review

한글을 시각화할 것이기 때문에 한글 폰트(.ttf파일)를 다운받아 DATA파일에 위치해 주세요.

그 후 워드클라우드 시각화를 진행해 줍니다.

# 한글 폰트 설정(.ttf파일 다운로드 후 실행)
wordcloud = WordCloud(DATA_PATH+'폰트.ttf').generate(' '.join(train_review))
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis('off')
plt.show()

영화, 진짜, 정말, 그냥, 너무 등등의 단어가 많이 나옴을 확인 가능합니다.

학습데이터의 긍정리뷰 및 부정리뷰가 얼만큼 되는지도 확인해 보겠습니다.

#긍정 1, 부정 0
print('긍정 리뷰 갯수: {}'.format(train_data['label'].value_counts()[1]))
print('부정 리뷰 갯수: {}'.format(train_data['label'].value_counts()[0]))

각각 74827개(1: 긍정), 75173개(0: 부정)가 있습니다.

대략적인 분석을 마치도록 하겠습니다.

이번에는 데이터를 전처리하여 학습할 수 있는 데이터로 만들어 주도록 하겠습니다.

데이터 전처리

데이터 전처리는 5단계로 이루어져 있습니다.

1. 정규화로 한국어만 남기기

2. 형태소 분석기로 어간 추출하기

3. 불용어 제거하기

4. 문자를 인덱스벡터로 전환하기

5. 패딩처리하기

한국어 텍스트를 전처리할 때는 konlpy를 사용하여 형태소 분석 등을 해주겠습니다.

!pip install konlpy

konlpy가 미설치 되어 있다면 위의 코드를 실행해 주세요.

그 후 학습데이터의 리뷰데이터만 뽑아 보겠습니다.

import numpy as np
import pandas as pd
import re
import json
from konlpy.tag import Okt
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.preprocessing.text import Tokenizer

DATA_PATH = '/content/sample_data/DATA/' # 데이터 경로 설정
train_data = pd.read_csv(DATA_PATH+'ratings_train.txt', header = 0, delimiter='\t', quoting=3)

train_data['document'][:5]

자 그럼 본격적으로 전처리를 시작해 보겠습니다.

1. 전처리를 도와주는 함수 만들기
#전처리 함수 만들기
def preprocessing(review, okt, remove_stopwords = False, stop_words =[]):
  #함수인자설명
  # review: 전처리할 텍스트
  # okt: okt객체를 반복적으로 생성하지 않고 미리 생성 후 인자로 받음
  # remove_stopword: 불용어를 제거할지 여부 선택. 기본값 False
  # stop_words: 불용어 사전은 사용자가 직접 입력, 기본값 빈 리스트

  # 1. 한글 및 공백 제외한 문자 모두 제거
  review_text = re.sub('[^가-힣ㄱ-ㅎㅏ-ㅣ\\s]','',review)
  
  #2. okt 객체를 활용하여 형태소 단어로 나눔
  word_review = okt.morphs(review_text,stem=True)

  if remove_stopwords:
    #3. 불용어 제거(선택)
    word_review = [token for token in word_review if not token in stop_words]
  return word_review
2. 전체 학습데이터 및 평가데이터 리뷰 전처리하기
# 전체 텍스트 전처리
stop_words = ['은','는','이','가','하','아','것','들','의','있','되','수','보','주','등','한']
okt = Okt()
clean_train_review = []

for review in train_data['document']:
  # 리뷰가 문자열인 경우만 전처리 진행
  if type(review) == str:
    clean_train_review.append(preprocessing(review,okt,remove_stopwords=True,stop_words= stop_words))
  else:
    clean_train_review.append([]) #str이 아닌 행은 빈칸으로 놔두기

clean_train_review[:4]

#테스트 리뷰도 동일하게 전처리
test_data = pd.read_csv(DATA_PATH + 'ratings_test.txt', header = 0, delimiter='\t', quoting=3)

clean_test_review = []
for review in test_data['document']:
  if type(review) == str:
    clean_test_review.append(preprocessing(review, okt, remove_stopwords=True, stop_words=stop_words))
  else:
    clean_test_review.append([])
3. 문자로 되어있는 리뷰데이터를 인덱스 벡터로 변환

학습데이터 리뷰로 단어 사전을 생성하여 리뷰데이터를 인덱스로 바꾸어 주도록 하겠습니다.

라벨데이터(긍정, 분석 감정데이터, 정답 데이터)는 벡터화 해줍니다.

# 인덱스 벡터 변환 후 일정 길이 넘어가거나 모자라는 리뷰 패딩처리
tokenizer = Tokenizer()
tokenizer.fit_on_texts(clean_train_review)
train_sequences = tokenizer.texts_to_sequences(clean_train_review)
test_sequences = tokenizer.texts_to_sequences(clean_test_review)

word_vocab = tokenizer.word_index #단어사전형태
MAX_SEQUENCE_LENGTH = 8 #문장 최대 길이

#학습 데이터
train_inputs = pad_sequences(train_sequences,maxlen=MAX_SEQUENCE_LENGTH,padding='post')

#학습 데이터 라벨 벡터화
train_labels = np.array(train_data['label'])

#평가 데이터 
test_inputs = pad_sequences(test_sequences,maxlen=MAX_SEQUENCE_LENGTH,padding='post')
#평가 데이터 라벨 벡터화
test_labels = np.array(test_data['label'])
4. 전처리 완료된 데이터 넘파이 파일로 저장

이후 여기서 만들어준 데이터들을 학습시 사용이 용이하도록 넘파이 파일로 만들어 저장해주도록 하겠습니다.

DEFAULT_PATH  = '/content/sample_data/' # 경로지정
DATA_PATH = 'CLEAN_DATA/' #.npy파일 저장 경로지정
TRAIN_INPUT_DATA = 'nsmc_train_input.npy'
TRAIN_LABEL_DATA = 'nsmc_train_label.npy'
TEST_INPUT_DATA = 'nsmc_test_input.npy'
TEST_LABEL_DATA = 'nsmc_test_label.npy'
DATA_CONFIGS = 'data_configs.json'

data_configs={}
data_configs['vocab'] = word_vocab
data_configs['vocab_size'] = len(word_vocab) + 1

#전처리한 데이터들 파일로저장
import os

if not os.path.exists(DEFAULT_PATH + DATA_PATH):
  os.makedirs(DEFAULT_PATH+DATA_PATH)

#전처리 학습데이터 넘파이로 저장
np.save(open(DEFAULT_PATH+DATA_PATH+TRAIN_INPUT_DATA,'wb'),train_inputs)
np.save(open(DEFAULT_PATH+DATA_PATH+TRAIN_LABEL_DATA,'wb'),train_labels)
#전처리 테스트데이터 넘파이로 저장
np.save(open(DEFAULT_PATH+DATA_PATH+TEST_INPUT_DATA,'wb'),test_inputs)
np.save(open(DEFAULT_PATH+DATA_PATH+TEST_LABEL_DATA,'wb'),test_labels)

#데이터 사전 json으로 저장
json.dump(data_configs,open(DEFAULT_PATH + DATA_PATH + DATA_CONFIGS,'w'),ensure_ascii=False)

저는 CLEAN_DATA라는 폴더에 저장해 주었습니다.

학습하기
1. 학습데이터 및 전처리 데이터 불러오기
# 학습 데이터 불러오기
import tensorflow as tf
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
from tensorflow.keras import layers
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import os
import json
from tqdm import tqdm

#전처리 데이터 불러오기
DATA_PATH = '/content/sample_data/CLEAN_DATA/'
DATA_OUT = '/content/sample_data/DATA_OUT/'
INPUT_TRAIN_DATA = 'nsmc_train_input.npy'
LABEL_TRAIN_DATA = 'nsmc_train_label.npy'
DATA_CONFIGS = 'data_configs.json'

train_input = np.load(open(DATA_PATH + INPUT_TRAIN_DATA,'rb'))
train_input = pad_sequences(train_input,maxlen=train_input.shape[1])
train_label = np.load(open(DATA_PATH + LABEL_TRAIN_DATA,'rb'))
prepro_configs = json.load(open(DATA_PATH+DATA_CONFIGS,'r'))
2. 파라미터 세팅하기
model_name= 'cnn_classifier_kr'
BATCH_SIZE = 512
NUM_EPOCHS = 10
VALID_SPLIT = 0.1
MAX_LEN = train_input.shape[1]

kargs={'model_name': model_name, 'vocab_size':prepro_configs['vocab_size'],'embbeding_size':128, 'num_filters':100,'dropout_rate':0.5, 'hidden_dimension':250,'output_dimension':1}
3. 모델 함수 만들기

학습 모델은 CNN분류 모델로 학습을 진행하도록 하겠습니다.

class CNNClassifier(tf.keras.Model):

  def __init__(self, **kargs):
    super(CNNClassifier, self).__init__(name=kargs['model_name'])
    self.embedding = layers.Embedding(input_dim=kargs['vocab_size'], output_dim=kargs['embbeding_size'])
    self.conv_list = [layers.Conv1D(filters=kargs['num_filters'], kernel_size=kernel_size, padding='valid',activation = tf.keras.activations.relu,
                                    kernel_constraint = tf.keras.constraints.MaxNorm(max_value=3)) for kernel_size in [3,4,5]]
    self.pooling = layers.GlobalMaxPooling1D()
    self.dropout = layers.Dropout(kargs['dropout_rate'])
    self.fc1 = layers.Dense(units=kargs['hidden_dimension'],
                            activation = tf.keras.activations.relu,
                            kernel_constraint=tf.keras.constraints.MaxNorm(max_value=3.))
    self.fc2 = layers.Dense(units=kargs['output_dimension'],
                            activation=tf.keras.activations.sigmoid,
                            kernel_constraint= tf.keras.constraints.MaxNorm(max_value=3.))
    

  def call(self,x):
    x = self.embedding(x)
    x = self.dropout(x)
    x = tf.concat([self.pooling(conv(x)) for conv in self.conv_list], axis = 1)
    x = self.fc1(x)
    x = self.fc2(x)
    return x
4. 학습하기

에포크는 10으로 주어 학습을 진행하고, 검증 정확도가 그전보다 낮아지면 학습을 멈추도록 설계하였습니다.

from tensorflow.keras.models import save_model

model = CNNClassifier(**kargs)
model.compile(optimizer=tf.keras.optimizers.Adam(),
              loss = tf.keras.losses.BinaryCrossentropy(),
              metrics = [tf.keras.metrics.BinaryAccuracy(name='accuracy')])

#검증 정확도를 통한 EarlyStopping 기능 및 모델 저장 방식 지정
earlystop_callback = EarlyStopping(monitor='val_accuracy', min_delta=0.0001, patience=2)
checkpoint_path = DATA_OUT + model_name +'\weights.h5'
checkpoint_dir = os.path.dirname(checkpoint_path)

if os.path.exists(checkpoint_dir):
  print("{} -- Folder already exists \n".format(checkpoint_dir))
else:
  os.makedirs(checkpoint_dir, exist_ok=True)
  print("{} -- Folder create complete \n".format(checkpoint_dir))

cp_callback = ModelCheckpoint(
    checkpoint_path, monitor = 'val_accuracy', verbose=1, save_best_only = True,
    save_weights_only=True
)

history = model.fit(train_input, train_label, batch_size=BATCH_SIZE, epochs = NUM_EPOCHS,
                    validation_split=VALID_SPLIT, callbacks=[earlystop_callback, cp_callback])
# 모델 저장하기
save_model(model,'모델 저장할 폴더 경로')

 

평가하기

위에서 학습한 모델이 저장이 되었고, 그 저장된 모델을 가지고 평가데이터를 넣어 얼마나 정답을 맞추는지 검증해 보도록 하겠습니다.

INPUT_TEST_DATA = 'nsmc_test_input.npy'
LABEL_TEST_DATA = 'nsmc_test_label.npy'
SAVE_FILE_NM = 'weights.h5'

test_input = np.load(open(DATA_PATH+INPUT_TEST_DATA,'rb'))
test_input = pad_sequences(test_input,maxlen=test_input.shape[1])
test_label_data = np.load(open(DATA_PATH + LABEL_TEST_DATA, 'rb'))

model.load_weights('모델저장위치/weights.h5')
model.evaluate(test_input, test_label_data)
 

약 82.6%의 정확도를 보입니다.

예측하기

마지막으로, 저장된 학습모델을 가지고 새로운 문장이 있을 때 그 문장이 긍정인지 부정인지 예측해 보겠습니다.

import numpy as np
import pandas as pd
import re
import json
from konlpy.tag import Okt
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.preprocessing.text import Tokenizer
okt = Okt()
tokenizer  = Tokenizer()

DATA_CONFIGS = 'data_configs.json'
prepro_configs = json.load(open('/content/sample_data/CLEAN_DATA/'+DATA_CONFIGS,'r'))
prepro_configs['vocab'] = word_vocab

tokenizer.fit_on_texts(word_vocab)

MAX_LENGTH = 8 #문장최대길이

sentence = input('감성분석할 문장을 입력해 주세요.: ')
sentence = re.sub(r'[^ㄱ-ㅎㅏ-ㅣ가-힣\\s ]','', sentence)
stopwords = ['은','는','이','가','하','아','것','들','의','있','되','수','보','주','등','한'] # 불용어 추가할 것이 있으면 이곳에 추가
sentence = okt.morphs(sentence, stem=True) # 토큰화
sentence = [word for word in sentence if not word in stopwords] # 불용어 제거
vector  = tokenizer.texts_to_sequences(sentence)
pad_new = pad_sequences(vector, maxlen = MAX_LENGTH) # 패딩

model.load_weights('/content/sample_data/DATA_OUT/cnn_classifier_kr\weights.h5') #모델 불러오기
predictions = model.predict(pad_new)
predictions = float(predictions.squeeze(-1)[1])

if(predictions > 0.5):
  print("{:.2f}% 확률로 긍정 리뷰입니다.\n".format(predictions * 100))
else:
  print("{:.2f}% 확률로 부정 리뷰입니다.\n".format((1 - predictions) * 100))

이렇게 직접 리뷰 문장을 입력하여 긍정리뷰인지 부정리뷰인지 확인이 가능합니다 :)

전체 코드

https://colab.research.google.com/drive/1PkuR9r9WrAXHBq3TLePCiOEgYwuFx2lO?usp=sharing

 

영화리뷰 감정분류(한국어).ipynb

Colaboratory notebook

colab.research.google.com

학습된 모델파일

https://drive.google.com/drive/folders/13FqdLc-8BbtMptJZgtaN390Ot96J8I4y?usp=sharing 

my_models.zip파일입니다.

 

Python감정분석_NLP - Google Drive

이 폴더에 파일이 없습니다.이 폴더에 파일을 추가하려면 로그인하세요.

drive.google.com

Github

https://github.com/ElenaLim/NLP_EmotionA.git

 

GitHub - ElenaLim/NLP_EmotionA: this repository is for Korean NLP. 한국어 영화리뷰 감정분석

this repository is for Korean NLP. 한국어 영화리뷰 감정분석. Contribute to ElenaLim/NLP_EmotionA development by creating an account on GitHub.

github.com

전처리, 학습, 검증, 예측의 각 파트가 분리된 .py 파일이 있습니다.

참고자료

책 - 텐서플로2와 머신러닝으로 시작하는 자연어처리

마무리

오늘 감정분석 대표적인 영화리뷰 데이터로 감정분류를 해 보았는데

개인적으로는 예측 부분이 가장 재밌는것 같습니다 ㅎㅎ

다른 오픈데이터도 있다면 시간될 때 다른 모델, 데이터로 감정 분류를 진행해 보도록 하겠습니다 :-)

++22.06.09 : 모델 저장부분 추가 및 학습된 모델 업로드

++22.09.07: 전처리, 학습, 검증, 예측 파트로 분리된 각각의 .py파일 추가(깃허브 링크)

반응형
반응형

안녕하세요. 오늘은 선형회귀를 푸는 알고리즘 중 하나인 경사하강법, 오차역전파에 관련한 포스팅을 진행하겠습니다.

그 전 포스팅에서 회귀문제를 풀 때는

y = wx + b 

(w는 가중치, b는 절편)

위의 식에서 데이터를 잘 예측할 수 있게 해주는 w,b값을 찾는 과정을 거쳐야 한다고 언급하였습니다.

이번 포스팅은 이 과정이 어떻게 진행되어 최적값을 찾는지 알아보는 시간을 갖도록 하겠습니다.

 

데이터 준비

데이터는 이전 포스팅에도 사용한 공부시간 및 시험점수 데이터를 사용하겠습니다.

https://www.kaggle.com/jahidsizansani/students-study-hour

 

Students Study Hour

 

www.kaggle.com

위의 링크에 들어가 csv파일을 다운받아 주세요.

데이터 확인

다음으로 다운받은 csv파일을 판다스로 확인해보도록 하겠습니다.

## 판다스로 데이터 확인 ##
import pandas as pd
study = pd.read_csv('Student Study Hour V2.csv')
print(study.shape)
study.head()

독립변수 및 종속변수 설정

우리는 공부하는 시간에 따른 시험 점수를 예측하고 싶습니다.

이 때, 이 문제를 풀 때 필요한 독립 및 종속변수를 설정해 줍니다.

독립변수(x)는 공부시간(Hours), 종속변수(y)는 시험점수(Scores)로 설정하겠습니다.

## 독립 및 종속변수 설정 ##
x_study = list(study['Hours'])
y_study = list(study['Scores'])

여기서 이제 y = wx + b 라는 식에 가중치(w)와 절편을(b) 찾아야 합니다.

이를 경사하강법을 사용하여 찾아보도록 하겠습니다.

선형회귀- 경사하강법

경사하강법은 기울기(변화율)를 사용하여 모델을 조금씩 조정하여 최적의 모델을 찾는 알고리즘입니다.

경사하강법은 아래와 같은 단계로 진행됩니다.

1. 랜덤으로 w와 b 정하기(랜덤숫자로 모델 만들기)
2. x값 중 하나를 선택해서 y값(예측값 구하기)
3. 2번에서 구한 예측값 y와 2번에서 사용한 x값의 실제 y(결과)값 비교
4. 예측값과 실제값이 거의 같아지도록 w,b 조정(모델 조정)
5. 데이터셋의 모든 x값을 처리할 때까지 2~4번 내용 반복
step1. 가중치(w)와 절편(b) 초기화

랜덤으로 w와 b의 값을 정합니다.

여기서는 1이라는 숫자를 각각 w와 b로 할당하여 모델을 만들어 보도록 하겠습니다.

# 1. w와 b를 초기화(랜덤으로 값 정함)
w = 1
b = 1
##이 떄 랜덤으로 만들어진 모델은 y = x + 1

위에서 만들어진 y = x + 1을 가지고 예측값을 구해 보겠습니다.

 

step2. x값을 대입하여 예측값 구하기

x값으로 위에서 만든 공부시간 리스트 중 0번째 값을 사용하여 예측값 y를 구하는 방법은 아래와 같습니다.

# 2. 랜덤 x값 넣어서 예측값 구해보기
y_model = x_study[0] * w + b
y_model

 3.5

실제 y의 값은

##실제 y값
y_study[0]

21

입니다. 원래의 값과 많은 차이가 있음을 확인할 수 있습니다.

 

step3. 예측값과 실제값의 차이 비교
#3. 예측값과 실제값의 차이 비교
y_study[0]-y_model

17.5

차이가 크네요. 가중치를 더 늘려야 할 것으로 보입니다.

step4. w(가중치)변경하여 예측값 구하기

가중치(w)를 0.1 만 증가시켜 다음 예측값을 측정해 보겠습니다.

#4. w(가중치)를 변경하여 예측값 측정
w_add = w + 0.1
y_model_add = x_study[0] * w_add + b
y_model_add

3.75

그전 결과인 3.5보다 조금 증가함을 확인 가능합니다.

step5. w의 증가량에 대비해 예측값이 얼마나 증가했는지 계산

이 때, 가중치가 전보다 0.1 늘었을 때 y_model이 얼마나 증가하였는지 변화율을 구해보면 아래와 같습니다.

#5. w가 0.1만큼 증가했을 때 y_model이 얼마나 증가했는지 계산
# =(y_model 증가량 / w 증가량)
w_rate = (y_model_add - y_model) / (w_add - w)
w_rate

2.4999999999

약 2.5 의 변화율이 나왔습니다.

이는 x값의 0번째값과 같습니다.

#위에서 구한 변화율은 x[0] 과 같음
x_study[0]

2.5

즉, w변화율은 x값임을 확인할 수 있습니다.

step6. 변화율로 가중치 w 업데이트

위에서 구한 변화율(w_rate)로 다음에 사용할 가중치를 정하도록 하겠습니다.

# 6. 변화율로 가중치 업데이트
w_new = w + w_rate
w_new

3.4999999999

다음에 사용할 w는 3.49999입니다.

이제 절편 b도 w변화율을 구할 때처럼 b 변화율을 구하여 업데이트 해봅시다.

 

step7. 변화율로 절편 b 업데이트
#7.변화율로 절편 업데이트
#b 증가율에 따른 y_model 값 증가값을 계산 후 변화율 계산
b_add = b + 0.1
y_model_add = x_study[0]*w + b_add
y_model_add

3.6

b도 0.1 만 증가시킨 후 y_model의 예측값을 구해보면 3.6 이라는 값이 나옵니다.

여기서 절편이 전보다 0.1 늘었을 때 y_model이 얼마나 증가하였는지 변화율을 보면,

#다음 절편 값 구하는 과정
b_rate = (y_model_add - y_model) / (b_add-b)
b_rate

1.0

1임을 확인할 수 있습니다. 0.1이 아니라 다른 값을 추가하여 변화율을 구하여도 1이 됩니다.

때문에 다음 스텝에서 진행할 새로운 절편 b의 값은 아래와 같습니다.

# 다음 스텝에서 진행할 새로운 b값
b_new = b + 1
b_new

2

경사하강법은 이 방법을 계속 반복하여 최적의 모델을 찾게 됩니다.

하지만, 이는 (1)예측값이 실제 값보다 한참 작은 경우 큰 폭으로 변화율을 줄 수 없고,

(2)예측값이 실제값 보다 큰 상황에서는 변화율을 감소시켜야 하는데 감소시킬 수 없다는 문제점이 있습니다.

이를 해결하기 위한 방법이 바로 '오차역전파(backpropagation)' 입니다.

오차역전파(backpropagation)

오차역전파는 실제값과 예측값의 차이를 이용하여 w와 b를 정합니다.

찾는 방법은 아래와 같습니다.

1. 오차와 변화율을 곱해 다음에 사용할 새로운 가중치 정하기
2. 1번에서 구한 가중치로 다음 x값에 적용하여 업데이트할 가중치 정하기
step1. (변화율 x 오차)로 가중치 업데이트

실제값 - 예측값을 하여 오차를 구하고,

그 오차를 각 w,b의 변화율에 곱한 후 그 값을 더하여 다음에 사용할 새로운 w,b 값을 만듭니다.

#1.변화율 * 오차로 가중치 업데이트
error = y_study[0] - y_model
w_new = w + w_rate *error
b_new = b + 1*error
w_new, b_new

(44.749999999999964, 18.5)

이제 이 각각의 값을 가진 모델을 만들어 공부시간x중 첫번째 값을 넣어 결과를 확인하여 

오차를 구해 가중치를 업데이트해 나갑니다.

#2. x_study[1]을 사용해 오차를 구하고 1번과정과 마찬가지로 그 다음의 w,b값 찾기
y_model = x_study[1] * w_new + b_new
error = y_study[1] - y_model
w_rate = x_study[1] #x값 자체가 변화율이므로
w_new = w_new + w_rate * error
b_new = b_new + 1 * error
w_new, b_new

(-973.8474999999988, -181.2249999999998)

위를 모든 x값을 대입하며 반복하여 최적의 모델을 찾아냅니다.

#모든 x값 반복하여 w,b구하기
for x_i, y_i in zip(x_study,y_study):
  y_model = x_i*w+b
  error = y_i - y_model
  w_rate = x_i
  w = w+w_rate*error
  b = b + 1*error

w, b

(-3.7026494779228295e+34, -5.968245924096763e+33)

위의 값을 이용해 시험점수를 구하면 아래와 같습니다.

y_hat = -3.7*x_study[0] + -5.97
y_hat

-15.219999999999999

아직도 실제 값인 21과는 전혀 다릅니다.

때문에 전체 x값을 20번씩 학습하여 최적의 모델을 찾아보도록 하겠습니다.

학습을 진행하다 inf 값이 나오면 더이상 최적의 값은 없다고 가정후 

학습을 중단하여 w,b 값을 반환하겠습니다.

#학습 반복하여 더욱 향상된 모델 찾기
for i in range(1,20):
  for x_i, y_i in zip(x_study,y_study):
    y_model= x_i*w+b
    if y_model == float('inf'):
      break
    else:
      error = y_i - y_model
      w_rate = x_i
      w = w+w_rate * error
      b = b+1*error
w,b

(7.3379121105182e+307, 2.3866622236073046e+307)

최종 w,b값이 나왔습니다.

이를 모델로 하여 결과를 구해보도록 하겠습니다.

new_ymodel = 7.34*x_study[0] + 2.39
new_ymodel

20.740000000000002

y_study[0]

21

위의 모델이 예측한 값과 실제값이 거의 일치함을 확인할 수 있습니다.

데이터와 가장 잘 맞는 수식 결과

전체 코드

https://colab.research.google.com/drive/1QFzjlztSWllPwjV4pJQRjr3zDVbkdpeH?usp=sharing 

 

ML동작방법.ipynb

Colaboratory notebook

colab.research.google.com

전체코드를 링크로 공유하오니 필요하신 분들은 사본을 만들어 사용하시면 됩니다:)

참고자료

책 - 정직하게 코딩하며 배우는 딥러닝 입문

마무리

저번 시간에 이어 회귀문제에서 어떻게 최적의 모델을 찾아가는지 그 과정을 자세히 알아보았습니다.

관련한 질문이 있거나 다음에 배우고 싶은 내용이 있다면 댓글 남겨주세요 :)

항상 제 글을 읽어주셔서 감사합니다.^0^

반응형

'ML' 카테고리의 다른 글

[python/ML] 머신러닝(Machine Learning) - 회귀  (0) 2021.12.21
반응형

오늘은 머신러닝의 기초가 되는 알고리즘 중 하나인 회귀를 사용하여 문제를 해결하는 방법을 알아보도록 하겠습니다.

머신 러닝(Machine Learning)이란?

머신러닝은 기계학습이라고도 합니다.

수많은 데이터를 컴퓨터에게 학습시켜 그 속에 있는 패턴을 찾아내서 데이터를 사람의 도움 없이 분류하거나 미래를 예측하는 방법이라고도 할 수 있습니다.

머신러닝에서는 지도학습 비지도 학습, 강화학습 등으로 나뉘는데

회귀는 그 중에서도 지도학습에 속합니다.

머신러닝의 흐름

기계학습을 할 때는 보통 아래와 같은 흐름을 가지고 진행합니다.

  1. 데이터 수집 전처리
  2. 데이터 저장
  3. 데이터 학습(학습방법 선택, 매개변수 조정, 학습반복 등)
  4. 평가 및 검증
지도학습 이란?

 지도학습은 간단히 말해서 기계를 학습할 때 정답을 같이 알려주어 학습하는 방법입니다.

사람이 공부를 할 때 문제지를 읽고 답을 채점하여 학습하는 것처럼

기계도 마찬가지로 어떤 데이터가 있으면 그것의 답을 같이 알려주어 학습을 시키는 방법입니다.

그리고 학습된 내용을 토대로 하여 다른 데이터의 답을 스스로 구할 수 있도록 합니다.

문제와 그에대한 답이 있는 지도학습

 

회귀(Regression)란?

지도학습에서 회귀(Regression)는 수치예측을 할때 쓰입니다.

정확히는 선형회귀(Linear Regression)가 쓰이는데 선형회귀는 아래와 같은 수식으로 나타낼 수 있습니다.

여기서 a는 기울기(slope), b는 절편(intercept)을 의미합니다.

회귀는 바로 위의 1차함수의 a,b값을 찾아 y값을 찾아내는 방법을 말합니다.

x는 독립변수가 되고 x에 의해 y가 정해지기 때문에 y는 x의 종속변수가 됩니다.

 

회귀 예제 - 학습 시간에 따른 시험 점수 예측

오늘은 회귀 예제로 학습시간에 따른 시험점수를 예측해 보도록 하겠습니다.

이번에 사용할 데이터는 kaggle에서 제공하는 단순한 공부 시간 및 점수를 가지고 학습 및 예측을 진행해 보겠습니다.

1. 데이터 준비

아래의 링크에서 csv파일을 다운받아 주세요.

https://www.kaggle.com/jahidsizansani/students-study-hour

 

Students Study Hour

 

www.kaggle.com

2. 데이터 확인

그럼 이제 pandas의 .shape() 와 head()를 사용하여 데이터를 확인해 보도록 하겠습니다.

## 판다스로 데이터 확인 ##
import pandas as pd
study = pd.read_csv('Student Study Hour V2.csv')
print(study.shape)
study.head()

Student Study Hour V2.csv 는 28개의 행을 가지고 2개의 열(Hours(공부시간), Scores(점수))을 가졌음을 확인 가능합니다.

3. 독립 및 종속변수 설정

회귀를 사용할 때는 x, y값을 정해 주어야 하기 때문에 x(독립변수)는 공부시간, 우리가 구하고자 하는 점수를 y(종속변수)로 사용하도록 하겠습니다.

## 독립 및 종속변수 설정 ##
x_study = study[['Hours']]
y_study = study[['Scores']]
print(x_study.shape, y_study.shape)
print(x_study.head(2))
print(y_study.head(2))

이렇게 28행 x 1열의 독립(x) 변수 및 종속(y) 변수를 설정하였습니다.

4. 모델 생성

이제 예측 값을 구하기위한 학습을 진행해 보겠습니다.

학습을 진행하려면 모델을 만들어 그 모델로 학습을 진행하게 됩니다.

우리는 간단히 경력이라는 데이터를 넣어 연봉 값을 구하고자 하기 때문에,

입력 = 1 크기의 층을 넣어주어 출력값(점수) 1개를 가지는 모델을 만들어 주도록 하겠습니다.

그리고 만들어진 모델에 대한 평가 함수로 MSE(Mean Squared Error, 평균 제곱 오차)를 사용하여 이 오차를 최소로 하는 a(기울기)와 b(절편값)를 찾아보도록 하겠습니다.

MSE는 수치예측 모델 평가 시에 주로 사용하며

x에 대한 (실제 y값- 예측값) 을 제곱하고 모두 더하여 평균을 구하는 함수입니다.

MSE 수식

tensorflow를 사용하여 모델을 만들어 보겠습니다.

tensorflow가 설치가 안되어있다면

!pip install tensorflow 를 입력하여 설치 후 사용해 주세요.

#!pip install tensorflow
# 모델을 생성합니다. 
import tensorflow as tf
X = tf.keras.layers.Input(shape=[1])
Y = tf.keras.layers.Dense(1)(X)
model = tf.keras.models.Model(X, Y)
model.compile(loss="mse")

그럼 이제 학습을 위한 모델 생성이 완료되었습니다.

5. 학습

이제 위에서 만들어진 모델을 가지고 학습을 진행하여 보겠습니다.

학습을 진행할 때에는 tensorflow의 .fit()메서드를 사용하여 학습을 진행합니다.

위에서 정한 독립, 종속 변수를 위에서 만든 모델을 넣고 15000번 학습을 진행해 보겠습니다.

verbose = 0으로 넣어주어 프로그레스를 생략하도록 하겠습니다.

시간이 오래 걸리지만 에포크당 손실이 어떻게 변하는지 확인하고 싶은 분은 verbose=1로 바꾸어 주세요.

# 모델에 데이터를 학습합니다. 
model.fit(x_study, y_study, epochs=15000, verbose=0)

학습된 모델이 어떻게 기울기와 절편이 설정되었는지 확인해 보고 싶으면, get_weights()를 사용하여 확인 가능합니다.

model.get_weights()
[array([[9.676896]], dtype=float32), array([3.2012239], dtype=float32)]

위의 모델은 기울기(a)가 9.676896, 절편(b)가 3.2012239 입니다.

이것을 수식으로 나타내면

y(점수) = 9.676896 * x(공부시간) + 3.2012239 로 나타낼 수 있습니다.

6. 예측

이제 학습된 모델로 예측을 해 보겠습니다.

원래는 테스트셋을 학습, 테스트로 나누어 진행하여야 하지만 데이터셋의 양 자체가 적어 x값을 넣어 주고 그 결과를 잘 맞추었는지 확인하도록 하겠습니다.

# 모델을 이용합니다. 
model.predict(x_study)

위의가 공부시간(x)에따른 y (점수)값입니다.

실제 y값은 아래와 같습니다.

#실제 y 값
y_salary

실제와 똑같지는 않지만 비슷하게 예측한 것을 확인할 수 있습니다. 더욱 정확한 예측값을 원한다면

epochs 를 더 늘려서 학습을 진행해 주시면 됩니다 :)

전체 코드
## 판다스로 데이터 확인 ##
import pandas as pd
study = pd.read_csv('Student Study Hour V2.csv')
print(study.shape)
study.head()

## 독립 및 종속변수 설정 ##
x_study = study[['Hours']]
y_study = study[['Scores']]
print(x_study.shape, y_study.shape)
print(x_study.head(2))
print(y_study.head(2))

## 모델을 생성합니다. 

X = tf.keras.layers.Input(shape=[1])
Y = tf.keras.layers.Dense(1)(X)
model = tf.keras.models.Model(X, Y)
model.compile(loss="mse")

# 모델에 데이터를 학습합니다. 
model.fit(x_study, y_study, epochs=15000, verbose=0)
#가중치 확인
model.get_weights()

# 모델을 이용합니다. 
model.predict(x_study)
#실제 y 값
y_salary
코드 파일

Linear_regression.ipynb
0.02MB

참고 자료

- https://opentutorials.org/course/4548

 

머신러닝1 - 생활코딩

수업소개 이 수업은 인공지능을 구현하는 기술인 머신러닝(Machine learning)을 다루는 수업입니다.  수업대상 인공지능과 머신러닝이 궁금한 분들 초등학생부터 어르신까지 누구나 수학과 코딩 때

opentutorials.org

- (책) 정직하게 코딩하며 배우는 딥러닝입문

반응형

'ML' 카테고리의 다른 글

[python/ML] 회귀 - 경사하강법, 오차역전파  (2) 2021.12.28
반응형

안녕하세요! 오늘은 matplotlib에 이어 seaborn 라이브러리로 그래프 그리는 방법을 알아보도록 하겠습니다.

그래프로 시각화할 데이터는 전의 게시물에서 사용한 마케팅 데이터셋을 그대로 사용하겠습니다.

데이터 준비

https://www.kaggle.com/imakash3011/customer-personality-analysis

 

Customer Personality Analysis

Analysis of company's ideal customers

www.kaggle.com

 

데이터 불러오기 및 폰트 설정
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import font_manager,rc
import seaborn as sns

# 한글 폰트 설정
font_location = 'C:/Windows/Fonts/MALGUNSL.TTF' #맑은고딕
font_name = font_manager.FontProperties(fname=font_location).get_name()
rc('font',family=font_name)

#데이터 셋 불러오기
df = pd.read_csv('marketing_campaign.csv',sep='\t')

 

밀집도 그래프, 히스토그램

seaborn 라이브러리에서는 distplot을 이용하면 히스토그램과 밀집도 그래프를 동시에 그릴 수 있습니다.

고객의 매장 구매량 정보를 히스토그램 및 밀집도 그래프로 시각화하여 보겠습니다.

### seaborn으로 그래프 그리기 ###
## 밀집도 그래프와 히스토그램 같이 그리기 ##
# 그래프 바탕 생성
ax = plt.subplots()
# 밀집도 그래프 없애려면 kde=False 추가, 밀집도만 남기려면 hist=False 추가
ax = sns.distplot(df['NumStorePurchases'],kde=True,hist=True,bins=13) 
# 제목 생성
ax.set_title('매장구매 밀집도&히스토그램')
# x라벨
ax.set_xlabel('매장구매')
# y라벨
ax.set_ylabel('빈도')
#그래프 popup
plt.show()

만약 히스토그램 그래프만 남기고 싶으면 sns.distplot(kde = False)로 바꾸어 주면 됩니다.

밀집도만 남기고 싶을 때는 sns.distplot(hist = False)로 바꾸어 주시면 됩니다.

또 seaborn에서는 rug 그래프(양탄자 그래프)를 그려 데이터의 밀집 정도를 확인할 수 있습니다.

# rug 추가
ax1 = plt.subplots()
ax1 = sns.displot(df['NumStorePurchases'],kde = True,rug=True)
ax1.set_titles('매장구매 히스토그램 양탄자그래프')
ax1.set_xlabels('매장구매')
plt.show()

seabron.distplot()에 rug = True를 추가하면 만들 수 있습니다.

count 그래프

이번엔 빈도 수를 세어 주는 count 그래프를 countplot을 사용하여 그려 보도록 하겠습니다.

count그래프는 이산값을 이용하여 그리는데, 오늘 예제에서는 학력을 기준으로 count 그래프를 만들어 보겠습니다.

## count 그래프 그리기(이산값) ##
ax2 = plt.subplots()
ax2 = sns.countplot('Education',data=df)
ax2.set_title('학력별 인원(명)')
ax2.set_xlabel('학력')
ax2.set_ylabel('해당 인원 숫자')
plt.show()

이렇게 고객의 학력을 전체적으로 파악할 수 있습니다.

산점도 그래프

위의 그래프까지는 변수 1개를 그래프로 그려보았습니다.

이번엔 변수 2개를 사용하여 산점도 그래프를 그려 보도록 하겠습니다.

산점도는 regplot을 이용하여 그릴 수 있습니다.

육류구매량을 x, 와인구매량을 y로 하여 산점도를 그려 보겠습니다.

##이변량그래프 그리기##
# 산점도 그래프 그리기
ax3 = plt.subplots()
ax3 = sns.regplot(x='MntMeatProducts',y='MntWines',data=df, fit_reg=True) #회귀선 제거 시 fig_reg=False
ax3.set_title('육류 및 와인 구매량 산점도')
ax3.set_xlabel('육류구매량')
ax3.set_ylabel('와인구매량')
plt.show()

regplot은 회귀선까지 같이 그려지는데 회귀선을 제거하고 싶으면

sns.regplot(fit_reg = False)로 바꿔주면 됩니다.

또한 jointplot을 사용하여 산점도와 히스토그램을 동시에 그릴 수도 있습니다.

# 산점도&히스토그램 그리기
joint = sns.jointplot(x='MntMeatProducts',y='MntWines',data=df)
joint.set_axis_labels(xlabel='육류구매량',ylabel='와인구매량')
joint.fig.suptitle('육류 및 와인구매량 산점도&히스토그램',fontsize=10)
plt.show()

육각 그래프

이번에는 그래프의 데이터를 구분하기 용이한 육각 그래프를 만들어 보겠습니다.

x값은 매장구매량, y값은 웹사이트 구매량으로 하는 육각 그래프는 jointplot의 kind='hex'를 사용하여 생성 가능합니다.

#육각그래프 그리기
hexbin = sns.jointplot(x='NumStorePurchases',y='NumWebPurchases',data=df,kind='hex')
hexbin.set_axis_labels(xlabel='매장구매',ylabel='웹사이트구매')
hexbin.fig.suptitle('매장 및 웹사이트 구매 육각그래프',fontsize=10)
plt.show()

산점도와 마찬가지로 위, 오른쪽의 히스토그램을 지워주고 싶으면

sns.regplot(fit_reg = False)로 바꿔주면 됩니다.

이차원 밀집도

이차원 밀집도는 kdeplot을 사용하여 그릴 수 있습니다. 결과물은 등고선 처럼 표현이 됩니다.

육류구매량을 x, 와인구매량을 y로 하여 이차원 밀집도를 그려보겠습니다.

#이차원 밀집도 그리기
ax4 = plt.subplots()
ax4 = sns.kdeplot(data=df['MntMeatProducts'],
                  data2=df['MntWines'],
                  shade=True) #shade=True 음영효과 설정
ax4.set_title('이차원밀집도(와인 및 육류 구매량)')
ax4.set_xlabel('육류구매량')
ax4.set_ylabel('와인구매량')
plt.show()

kdeplot(shade = True)로 설정하여 음영을 줄 수 있습니다.

위의 그래프는 음영을 준 상태입니다.

박스그래프

이번엔 이산값과 연속값을 시각화할 수 있는 박스그래프를 그려보도록 하겠습니다.

x는 학력, y는 수입으로 잡고 boxplot을 사용하여 그래프를 생성하겠습니다.

#박스그래프 그리기
ax4 = plt.subplots()
ax4 = sns.boxplot(x='Education',y='Income',data=df)
ax4.set_title('학력에 따른 수입 박스그래프')
ax4.set_xlabel('학력')
ax4.set_ylabel('수입')
plt.show()

바 그래프

바 그래프는 변수값의 평균을 계산하여 시각화가 가능합니다.

학력에 따른 수입의 평균을 barplot을 사용하여 그려보겠습니다.

#바그래프 그리기
ax_4 = plt.subplots()
ax_4 = sns.barplot(x='Education',y='Income',data=df)
ax_4.set_title('학력에 따른 수입 바그래프')
ax_4.set_xlabel('학력')
ax_4.set_ylabel('수입의 평균')
plt.show()

바이올린 그래프

바이올린 그래프는 박스그래프와 비슷하지만 데이터 분산을 더욱 잘 확인할 수 있습니다.

데이터 밀도를 추정하여 시각화하기때문입니다.

위에서와 마찬가지로 x=학력, y=수입으로 하는 바이올린 그래프를 violinplot을 사용하여 만들어 보겠습니다.

#바이올린그래프 그리기(데이터분산확인가능)
ax5 = plt.subplots()
ax5 = sns.violinplot(x='Education',y='Income',data=df)
ax5.set_title('학력에 따른 수입 바이올린그래프')
ax5.set_xlabel('학력')
ax5.set_ylabel('수입')
plt.show()

관계 그래프

seaborn으로는 여러 그래프를 한 번에 확인할 수 있는 관계 그래프를 그릴 수 있습니다.

seaborn의 pairplot을 사용하여 그릴 수 있는데,

map_upper은 대각선 위 3개 그래프,

map_lower은 대각선 아래 3개 그래프,

map_diag는 대각선상에 있는 나머지3개의 그래프를 지정하여 만들 수 있습니다.

여기서는 대각선 위의 그래프는 산점도로, 아래는 밀집도 그래프로, 나머지 대각선은 히스토그램으로

관계 그래프를 그려 보도록 하겠습니다.

원본 데이터셋의 열이 너무 많기 때문에, 육류구매랴야, 와인구매량, 웹사이트 구매량의 3변수만 뽑아내어

관계 그래프로 시각화 해 보겠습니다.

#데이터 다듬기
df2 = df.loc[:,['MntMeatProducts','MntWines','NumWebPurchases']]
print(df2.head())
#관계 그래프 그리기
pair_grid = sns.PairGrid(df2)
pair_grid = pair_grid.map_upper(sns.regplot) # 대각선 윗부분
pair_grid = pair_grid.map_lower(sns.kdeplot) # 대각선 아랫부분
pair_grid = pair_grid.map_diag(sns.histplot) # 대각선 중심
plt.show()

전체 코드
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import font_manager,rc
import seaborn as sns

# 한글 폰트 설정
font_location = 'C:/Windows/Fonts/MALGUNSL.TTF' #맑은고딕
font_name = font_manager.FontProperties(fname=font_location).get_name()
rc('font',family=font_name)

#데이터 셋 불러오기
df = pd.read_csv('marketing_campaign.csv',sep='\t')

print(df.head())

### seaborn으로 그래프 그리기 ###
## 밀집도 그래프와 히스토그램 같이 그리기 ##
# 그래프 바탕 생성
ax = plt.subplots()
# 밀집도 그래프 없애려면 kde=False 추가, 밀집도만 남기려면 hist=False 추가
ax = sns.distplot(df['NumStorePurchases'],kde=True,hist=True,bins=13) 
# 제목 생성
ax.set_title('매장구매 밀집도&히스토그램')
# x라벨
ax.set_xlabel('매장구매')
# y라벨
ax.set_ylabel('빈도')
#그래프 popup
#plt.show()
# rug 추가
ax1 = plt.subplots()
ax1 = sns.displot(df['NumStorePurchases'],kde = True,rug=True)
ax1.set_titles('매장구매 히스토그램 양탄자그래프')
ax1.set_xlabels('매장구매')
#plt.show()

## count 그래프 그리기(이산값) ##
ax2 = plt.subplots()
ax2 = sns.countplot('Education',data=df)
ax2.set_title('학력별 인원(명)')
ax2.set_xlabel('학력')
ax2.set_ylabel('해당 인원 숫자')
#plt.show()

##이변량그래프 그리기##
# 산점도 그래프 그리기
ax3 = plt.subplots()
ax3 = sns.regplot(x='MntMeatProducts',y='MntWines',data=df, fit_reg=True) #회귀선 제거 시 fig_reg=False
ax3.set_title('육류 및 와인 구매량 산점도')
ax3.set_xlabel('육류구매량')
ax3.set_ylabel('와인구매량')
#plt.show()

# 산점도&히스토그램 그리기
joint = sns.jointplot(x='MntMeatProducts',y='MntWines',data=df)
joint.set_axis_labels(xlabel='육류구매량',ylabel='와인구매량')
joint.fig.suptitle('육류 및 와인구매량 산점도&히스토그램',fontsize=10)
#plt.show()

#육각그래프 그리기

hexbin = sns.jointplot(x='NumStorePurchases',y='NumWebPurchases',data=df,kind='hex')
hexbin.set_axis_labels(xlabel='매장구매',ylabel='웹사이트구매')
hexbin.fig.suptitle('매장 및 웹사이트 구매 육각그래프',fontsize=10)
#plt.show()

#이차원 밀집도 그리기
ax4 = plt.subplots()
ax4 = sns.kdeplot(data=df['MntMeatProducts'],
                  data2=df['MntWines'],
                  shade=True) #shade=True 음영효과 설정
ax4.set_title('이차원밀집도(와인 및 육류 구매량)')
ax4.set_xlabel('육류구매량')
ax4.set_ylabel('와인구매량')
plt.show()

#박스그래프 그리기
ax4 = plt.subplots()
ax4 = sns.boxplot(x='Education',y='Income',data=df)
ax4.set_title('학력에 따른 수입 박스그래프')
ax4.set_xlabel('학력')
ax4.set_ylabel('수입')
plt.show()

#바그래프 그리기
ax_4 = plt.subplots()
ax_4 = sns.barplot(x='Education',y='Income',data=df)
ax_4.set_title('학력에 따른 수입 바그래프')
ax_4.set_xlabel('학력')
ax_4.set_ylabel('수입의 평균')
plt.show()

#바이올린그래프 그리기(데이터분산확인가능)
ax5 = plt.subplots()
ax5 = sns.violinplot(x='Education',y='Income',data=df)
ax5.set_title('학력에 따른 수입 바이올린그래프')
ax5.set_xlabel('학력')
ax5.set_ylabel('수입')
plt.show()

#데이터 다듬기
df2 = df.loc[:,['MntMeatProducts','MntWines','NumWebPurchases']]
print(df2.head())
#관계 그래프 그리기
pair_grid = sns.PairGrid(df2)
pair_grid = pair_grid.map_upper(sns.regplot) # 대각선 윗부분
pair_grid = pair_grid.map_lower(sns.kdeplot) # 대각선 아랫부분
pair_grid = pair_grid.map_diag(sns.histplot) # 대각선 중심
plt.show()
코드 파일

seaborn_ex.py
0.00MB

참고 자료
  • 책- Do it 데이터 분석을 위한 pandas 입문
마무리

오늘은 seaborn으로 그릴 수 있는 그래프들을 알아보았습니다.

seabron을 사용하면 matplotlib보다 화려하고 다양한 그래프를 만들 수 있습니다.

데이터 분석 시 활용하는걸 추천합니다. :-)

반응형
반응형

1편에 이어 matplotlib으로 그래프 만들기 2편 시작해 보도록 하겠습니다!

1편은 아래의 링크를 참고해주세요:)

https://wonhwa.tistory.com/30

 

[python/시각화] matplotlib으로 그래프 만들기- 히스토그램, 산점도, 박스그래프

안녕하세요! 오늘은 파이썬 matplotlib라이브러리를 이용해 다양한 종류의 그래프를 만들어 보도록 하겠습니다. 그럼 바로 시작해 보도록 하겠습니다. 데이터 준비 오늘 시각화할 데이터는 kaggle의

wonhwa.tistory.com

 

데이터준비

1편에서 사용한 csv데이터를 준비해 주세요:)

또는 아래의 링크에서 다운받아 주세요.

https://www.kaggle.com/imakash3011/customer-personality-analysis

 

Customer Personality Analysis

Analysis of company's ideal customers

www.kaggle.com

 

다변량 그래프 그리기

다변량 그래프는 변수가 여러 개 있는 그래프입니다.

이번 포스팅에는 변수를 4개를 추가하여 그래프를 그리는 방법을 알아보도록 하겠습니다.

  • x축: MntMeatProducts(육류구매량)
  • y축: MntWines(와인구매량)
  • 색구분: Edu_level(학력)
  • 사이즈구분: NumWebPurchases(웹사이트구매횟수)

이렇게 4개의 변수를 그래프로 표현해 보겠습니다.

기존 csv를 불러온 df에서 null 값이 있으면 0으로 일괄대체를 해준 후 나머지 과정을 진행합니다.

먼저 학력별로 색 구분을 하려면 str데이터인 학력을 문자에서 숫자로 변환하는 작업이 필요합니다.

이 작업을 아래의 함수를 써서 학력을 숫자로 바꾼 후,

바꾼 숫자들을 'Edu_level'이라는 학력 컬럼을 새로 만들어 입력 하겠습니다.

import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import font_manager,rc

# 한글 폰트 설정
font_location = 'C:/Windows/Fonts/MALGUNSL.TTF' #맑은고딕
font_name = font_manager.FontProperties(fname=font_location).get_name()
rc('font',family=font_name)
#데이터 셋 불러오기
df = pd.read_csv('marketing_campaign.csv',sep='\t')
# null값 0으로 대체
df = df.fillna(0)

########## 다변량 그래프 그리기 ###########
#다변량 그래프(3개 이상의 변수 사용)

# 학력부분 숫자로 바꾸기
def recode_edu(education_level):
    if education_level == 'Basic':
        return 0
    elif education_level == 'Graduation':
        return 1
    elif education_level == '2nCycle':
        return 2
    elif education_level == 'Master':
        return 3
    else:
        return 4

df['Edu_level'] = df['Education'].apply(recode_edu)
print(df.head())

출력:

맨 끝 컬럼에 Edu_level이 잘 추가되었음을 확인할 수 있습니다.

그 후 다변량 그래프를 그려주도록 합니다.

c = color(색)을, s = size(사이즈)를 의미합니다.

# x축: MntMeatProducts(육류구매량)
# y축: MntWines(와인구매량)
# c(컬러): Edu_level(학력)
# s(사이즈): NumWebPurchases(웹사이트구매횟수)

#그래프틀생성
scatter_plot = plt.figure()
axes1 = scatter_plot.add_subplot(1,1,1)
#산점도 다변량 그래프 그리기
axes1.scatter(
    x=df['MntMeatProducts'],
    y=df['MntWines'],
    c=df['Edu_level'],
    s=df['NumWebPurchases']*10,
    alpha=0.5
) #alpha는 투명도 조절
axes1.set_title('다변량 그래프(학력별 다른색상, 웹사이트구매횟수는 사이즈별')
axes1.set_xlabel('육류구매량')
axes1.set_ylabel('와인구매량')
plt.show()

이렇게 4개의 변수를 그래프로 시각화하였습니다.

 

밀집도 그래프

이번에는 'NumStorePurchases'(매장구매량)컬럼을 밀집도 그래프로 나타내 보겠습니다.

밀집도 그래프는 plot.kde()를 이용하여 생성할 수 있습니다.

####밀집도 그래프#####
ax1 = plt.subplot()
ax1 = df['NumStorePurchases'].plot.kde() #매장구매량
plt.show()

 

육각형 그래프

마지막으로, 육각형 그래프를 그려보도록 하겠습니다.

plot.hexbin을 사용하여 육각 그래프를 그릴 수 있고, gridsize 파라미터로 그래프 육각형의 크기를 조절할 수 있습니다.

x축은 'Income'(수입) 컬럼으로, y축은 'MntWines'(와인구매량) 컬럼으로 하여 육각형 그래프를 만들어 보겠습니다.

####육각형 그래프#####
fig2,ax2 = plt.subplots()
ax2 = df.plot.hexbin(x='Income',y='MntWines',ax=ax2,gridsize=10) #gridsize: 육각형크기조절
plt.show()

위와 같이 벌집모양의 육각형 그래프가 만들어졌습니다.

전체 코드
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import font_manager,rc

# 한글 폰트 설정
font_location = 'C:/Windows/Fonts/MALGUNSL.TTF' #맑은고딕
font_name = font_manager.FontProperties(fname=font_location).get_name()
rc('font',family=font_name)
#데이터 셋 불러오기
df = pd.read_csv('marketing_campaign.csv',sep='\t')
# null값 0으로 대체
df = df.fillna(0)

########## 다변량 그래프 그리기 ###########
#다변량 그래프(3개 이상의 변수 사용)

# 학력부분 숫자로 바꾸기
def recode_edu(education_level):
    if education_level == 'Basic':
        return 0
    elif education_level == 'Graduation':
        return 1
    elif education_level == '2nCycle':
        return 2
    elif education_level == 'Master':
        return 3
    else:
        return 4

df['Edu_level'] = df['Education'].apply(recode_edu)
print(df.head())

# x축: MntMeatProducts(육류구매량)
# y축: MntWines(와인구매량)
# c(컬러): Edu_level(학력)
# s(사이즈): NumWebPurchases(웹사이트구매횟수)

#그래프틀생성
scatter_plot = plt.figure()
axes1 = scatter_plot.add_subplot(1,1,1)
#산점도 다변량 그래프 그리기
axes1.scatter(
    x=df['MntMeatProducts'],
    y=df['MntWines'],
    c=df['Edu_level'],
    s=df['NumWebPurchases']*10,
    alpha=0.5
) #alpha는 투명도 조절
axes1.set_title('다변량 그래프(학력별 다른색상, 웹사이트구매횟수는 사이즈별')
axes1.set_xlabel('육류구매량')
axes1.set_ylabel('와인구매량')
plt.show()


####밀집도 그래프#####
ax1 = plt.subplot()
ax1 = df['NumStorePurchases'].plot.kde() #매장구매량
plt.show()

####육각형 그래프#####
fig2,ax2 = plt.subplots()
ax2 = df.plot.hexbin(x='Income',y='MntWines',ax=ax2,gridsize=10) #gridsize: 육각형크기조절
plt.show()
코드 파일

ex)matplotlib(2).py
0.00MB

참고 자료
  • 책 Do it! 데이터 분석을 위한 판다스 입문 - 이지스퍼블리싱

 

마무리

저번 편에 이어 matplotlib으로 그릴 수 있는 다른 그래프들을 더 알아보았습니다.

데이터 분석 시 시각화가 필요한 그래프가 있으면 위의 내용들을 활용하여 분석을 진행하면

데이터 인사이트를 얻기에도 쉬우리라 생각됩니다. ヾ(^▽^*)))

 

++3D 그래프 추가버전 및 기타설정은 아래에서 확인하실 수 있습니다.

https://wonhwa1.blogspot.com/2022/11/python-matplotlib-3d.html

 

[python] matplotlib으로 그래프 만들기- 다변량그래프+3d, 밀집도그래프, 육각그래프, 패턴, 텍스트 설

Matplotlib 그래프 2 1편은 아래에서 확인하실 수 있습니다:) https://wonhwa1.blogspot.com/2022/11/python-matplotlib.html 데이터 준비 1편에서 사용한 csv데이터를 준비해 주세요. 또는 아래의...

wonhwa1.blogspot.com

 

반응형
반응형

안녕하세요!

오늘은 파이썬 matplotlib라이브러리를 이용해 다양한 종류의 그래프를 만들어 보도록 하겠습니다.

그럼 바로 시작해 보도록 하겠습니다.

 

데이터 준비

오늘 시각화할 데이터는 kaggle의 'Customer Personality Analysis' Datasets를 이용하여 그래프를 시각화 해보겠습니다.

아래의 링크에서 csv파일을 다운받아 주세요:)

https://www.kaggle.com/imakash3011/customer-personality-analysis

 

Customer Personality Analysis

Analysis of company's ideal customers

www.kaggle.com

이 데이터는 한 회사 고객들의 구매 정보 및 고객 정보등을 포함하고 있습니다.

각 열의 내용은 아래와 같습니다.

People
ID: Customer's unique identifier (고객식별id)
Year_Birth: Customer's birth year (출생년도)
Education: Customer's education level (학력)
Marital_Status: Customer's marital status (결혼상태)
Income: Customer's yearly household income (수입)
Kidhome: Number of children in customer's household (자녀 수)
Teenhome: Number of teenagers in customer's household (10대 자녀 수)
Dt_Customer: Date of customer's enrollment with the company (회원가입날짜)
Recency: Number of days since customer's last purchase (마지막구매 후 경과일자)
Complain: 1 if the customer complained in the last 2 years, 0 otherwise (지난 2년간 컴플레인 여부)
Products
MntWines: Amount spent on wine in last 2 years (지난 2년간 와인 구매량)
MntFruits: Amount spent on fruits in last 2 years (지난 2년간 과일 구매량)
MntMeatProducts: Amount spent on meat in last 2 years (지난 2년간 육류 구매량)
MntFishProducts: Amount spent on fish in last 2 years (지난 2년간 수산물 구매량)
MntSweetProducts: Amount spent on sweets in last 2 years (지난 2년간 간식류 구매량)
MntGoldProds: Amount spent on gold in last 2 years (지난 2년간 귀금속 구매량)

그 밖에도 여러 열이 있는데 나머지는 위의 링크에 들어가면 확인할 수 있습니다 :)

 

필요모듈 import 및 폰트설정

오늘의 주인공이자 그래프 생성에 필요한 matplotlib 라이브러리와

데이터 불러오는 데 필요한 pandas 라이브러리를 불러와 줍니다.

그리고 그래프에 한글을 사용하기 위해서 한글 폰트를 설정해 주어야 하기 때문에 폰트설정까지 해 보도록 하겠습니다.

import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import font_manager,rc

# 한글 폰트 설정
font_location = 'C:/Windows/Fonts/MALGUNSL.TTF' #맑은고딕
font_name = font_manager.FontProperties(fname=font_location).get_name()
rc('font',family=font_name)

저는 '맑은 고딕'을 한글 폰트로 사용하겠습니다.

다른 폰트를 사용하고 싶다면 변경해 주시면 됩니다.

 

데이터셋 준비

위에서 다운받은 csv파일을 열어 줍니다.

이 csv파일은 ,가 아니라 tab으로 나누어져있어 sep = \t으로 설정하여 열어주어야 합니다.

그후 .head()를 사용하여 데이터 내용을 확인해 보도록 하겠습니다.

#데이터 셋 불러오기
df = pd.read_csv('marketing_campaign.csv',sep='\t')

print(df.head())

출력:

29개의 컬럼으로 데이터가 이루어져 있습니다.

각각 컬럼에 대한 설명은 위를 확인해 주세요.

이제 위의 데이터로 그래프를 만들어 보도록 하겠습니다.

히스토그램 그래프

히스토그램은 도수분포를 그래프화 시킨 건데 보통 변수 1개를 가지고 빈도를 구하여 그래프를 그립니다.

오늘 포스팅에는 고객의 자녀 수를 히스토그램으로 만들어 보도록 하겠습니다.

#############히스토그램##############
#그래프를 그리기 위한 기본 틀 생성
fig = plt.figure()
axes1=fig.add_subplot(1,1,1)

#히스토그램 그래프 만들기(변수1개)
axes1.hist(df['Kidhome'],bins = 8) #가정의 자녀 수 히스토그램 #bins는 x축 칸(간격)조정
#제목설정
axes1.set_title('고객 가정의 자녀 수 히스토그램')
#x축라벨링
axes1.set_xlabel('자녀 수')
#y축라벨링
axes1.set_ylabel('빈도')
plt.show()

위와 같이 히스토그램이 만들어 졌습니다.

데이터프레임으로도 히스토그램을 만들 수 있는데요 방법은 아래와 같습니다.

###다른방법으로 히스토그램
ax = plt.subplots()
ax = df['Kidhome'].plot.hist()
plt.show()

산점도 그리기

이번에는 matplotlib으로 산점도를 생성해보도록 하겠습니다.

산점도는 x,y 값을 점으로 찍어 그래프를 그리는방법인데,

여기서는 간식구매량을 x, 과일구매량을 y로 설정하여 산점도를 생성해 보겠습니다.

#산점도 그리기(변수2개)
scatter_plot = plt.figure()
axes2 = scatter_plot.add_subplot(1,1,1)

axes2.scatter(df['MntSweetProducts'],df['MntFruits'])
#제목설정
axes2.set_title('간식구매량 및 과일구매량 산점도')
#x축라벨링
axes2.set_xlabel('간식구매량')
#y축라벨링
axes2.set_ylabel('과일구매량')

#산점도 그리는 다른 방법
fig2,ax2 = plt.subplots()
ax2 = df.plot.scatter(x='MntSweetProducts',y='MntFruits',ax=ax2)
plt.show()

[산점도 그래프]

[df로 그린 산점도 그래프]

이렇게 2가지 방법으로 산점도를 그려 봤습니다.

 

박스그래프

이제 박스그래프를 그려보도록 하겠습니다.

박스그래프는 이산형 변수와 연속형 변수를 함께 사용하여 그리는데

이산형 변수는 성별의 male, female 과 같이 확실히 구분되는 값을 말하고,

연속형 변수는 구매량과 같은 연속적인 숫자가 있는 범위의 값을 말합니다.

이번에는 데이터의 Education(학력)을 이산형변수로,

Income(수입)을 연속형 변수로 하여 박스그래프를 그려 보도록 하겠습니다.

income값 중에 null인 값이 있어 null을 0으로 대체한 후 그래프를 생성하도록 합니다.

#############박스그래프##############
# box 그래프 그리기(이산형 변수와 연속형 변수를 함께 사용)
# 이산형: 학력
# 연속형: 수입
# df Null값 0으로 대체
df['Income'] = df['Income'].fillna(0)

boxplot = plt.figure()
axes3 = boxplot.add_subplot(1,1,1)
axes3.boxplot([df[df['Education'] == 'Basic']['Income'], 
               df[df['Education'] == 'Graduation']['Income'],
               df[df['Education'] == '2n Cycle']['Income'],
               df[df['Education'] == 'Master']['Income'], 
               df[df['Education'] == 'PhD']['Income']], 
               labels=['고졸','대졸','2nCycle','석사','박사'])

axes3.set_xlabel('학력')
axes3.set_ylabel('수입')
axes3.set_title('학력에 따른 수입 박스그래프')
plt.show()

여기서 Basic은 고등학교 졸업, Graduation은 학사, Master은 석사, PhD는 박사를 의미합니다.

2nCycle(second cycle)은 학사~석사 라고 하는데 석사 과정에 있는 사람을 말하는 것 같습니다.

혹시 2nCycle에대해 아는 분들은 댓글 남겨주세요 ㅎㅎ

그리고 df로도 박스 그래프를 그릴 수 있는데요 그전에 기존df의 피벗팅이 필요합니다.

아래와 같이 필요한 내용만 데이터를 뽑아 주세요.

# df피벗
#교육, 수입부분만뽑기
df_pv=df.iloc[:,0:5]
df_pv = df_pv.drop(['Year_Birth','Marital_Status'],axis=1) #열삭제시 axis=1
print(df_pv.head())

출력:

그 후 피벗을 진행해 줍니다.

#교육상태를 컬럼으로 피벗
df_pv = df_pv.pivot_table(
    index='ID',
    columns='Education',
    values='Income')
print(df_pv.head())

출력:

이제 다시 박스 그래프로 시각화 해보도록 하겠습니다.

#df로 박스그래프 만들기
fig3,ax3 = plt.subplots()
ax3 = df_pv.plot.box(ax= ax3)
plt.show()

위와 같이 그래프가 잘 만들어졌습니다. ㅎㅎ

전체 코드
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import font_manager,rc

# 한글 폰트 설정
font_location = 'C:/Windows/Fonts/MALGUNSL.TTF' #맑은고딕
font_name = font_manager.FontProperties(fname=font_location).get_name()
rc('font',family=font_name)
#데이터 셋 불러오기
df = pd.read_csv('marketing_campaign.csv',sep='\t')

print(df.head())

#############히스토그램##############
#그래프를 그리기 위한 기본 틀 생성
fig = plt.figure()
axes1=fig.add_subplot(1,1,1)

#히스토그램 그래프 만들기(변수1개)
axes1.hist(df['Kidhome'],bins = 8) #가정의 자녀 수 히스토그램 #bins는 x축 칸(간격)조정
#제목설정
axes1.set_title('고객 가정의 자녀 수 히스토그램')
#x축라벨링
axes1.set_xlabel('자녀 수')
#y축라벨링
axes1.set_ylabel('빈도')
#plt.show()

###다른방법으로 히스토그램
ax = plt.subplots()
ax = df['Kidhome'].plot.hist()
#plt.show()

#############산점도##############
#산점도 그리기(변수2개)
scatter_plot = plt.figure()
axes2 = scatter_plot.add_subplot(1,1,1)

axes2.scatter(df['MntSweetProducts'],df['MntFruits'])
#제목설정
axes2.set_title('간식구매량 및 과일구매량 산점도')
#x축라벨링
axes2.set_xlabel('간식구매량')
#y축라벨링
axes2.set_ylabel('과일구매량')


#산점도 그리는 다른 방법
fig2,ax2 = plt.subplots()
ax2 = df.plot.scatter(x='MntSweetProducts',y='MntFruits',ax=ax2)
#plt.show()

#############박스그래프##############
# box 그래프 그리기(이산형 변수와 연속형 변수를 함께 사용)
# 이산형: 학력
# 연속형: 수입
# df Null값 0으로 대체
df['Income'] = df['Income'].fillna(0)

boxplot = plt.figure()
axes3 = boxplot.add_subplot(1,1,1)
axes3.boxplot([df[df['Education'] == 'Basic']['Income'], 
               df[df['Education'] == 'Graduation']['Income'],
               df[df['Education'] == '2n Cycle']['Income'],
               df[df['Education'] == 'Master']['Income'], 
               df[df['Education'] == 'PhD']['Income']], 
               labels=['고졸','대졸','2nCycle','석사','박사'])

axes3.set_xlabel('학력')
axes3.set_ylabel('수입')
axes3.set_title('학력에 따른 수입 박스그래프')
#plt.show()

#df으로 box plot 그리기

# df피벗
#교육, 수입부분만뽑기
df_pv=df.iloc[:,0:5]
df_pv = df_pv.drop(['Year_Birth','Marital_Status'],axis=1) #열삭제시 axis=1
print(df_pv.head())

#교육상태를 컬럼으로 피벗
df_pv = df_pv.pivot_table(
    index='ID',
    columns='Education',
    values='Income')
print(df_pv.head())

fig3,ax3 = plt.subplots()
ax3 = df_pv.plot.box(ax= ax3)
plt.show()
코드파일

ex_matplotlib(1).py
0.00MB

참고자료
  • 책 Do it! 데이터 분석을 위한 판다스 입문 - 이지스퍼블리싱
마무리

오늘은 matplotlib로 그래프 그리는 방법을 알아보았는데요

다음 시간에는 matplotlib 2편으로 다른 그래프들도 그려보도록 하겠습니다!

궁금한 점은 댓글로 알려주세요:)

 

++ 파이그래프 추가한 글은 아래에서 확인하실 수 있습니다.

https://wonhwa1.blogspot.com/2022/11/python-matplotlib.html

 

[python] matplotlib으로 그래프 만들기- 히스토그램, 산점도, 박스그래프, 파이그래프

Matplotlib이란? matplotlib은 python에서 데이터 시각화를 도와주는 라이브러리입니다. 그럼 matplotlib을 이용해 다양한 종류의 그래프를 바로 그려 보도록 하겠습니다. 데이터 준비 오늘 시각화할 데이

wonhwa1.blogspot.com

 

반응형

+ Recent posts