반응형

안녕하세요.

그동안 python으로 여러 프로그램을 만들어 보았는데,

그걸 다른 사람에게도 보여주고 싶을 때는

1. python 설치

2. .py 파일 실행

이렇게 번거로운 과정이 필요할 것입니다.

하지만 그동안 만들었던 .py파일 프로그램을 .exe 파일로 만들 수 있다면

상대방 입장에서도 파일을 다운받아 실행하기만 하면 되니 엄청 간편할 것입니다.

이렇게 python 파일을 exe파일로 만들어주는 라이브러리가 있는데요,

그것은 바로 pyinstaller 라는 라이브러리 입니다.

 

pyinstaller 설치

설치 방법은 간단합니다. 터미널창에 아래와 같이 pip를 사용하여 간단히 설치할 수 있습니다.

pip install pyinstaller

 

pyinstaller 사용 방법

pyinstaller는 터미널에 여러 옵션을 주어 exe파일을 만들 수 있습니다.

그중 유용하게 쓰이는 옵션 몇가지를 알려드리자면,

--noconsole : exe파일 실행 시 콘솔창을 나타나지 않게 하기
--onefile : exe파일을 하나의 파일로 한번에 만들기
--icon: exe파일에 사용할 아이콘을 추가
--add-data: 데이터파일 추가

등등이 있습니다.

--icon 옵션을 사용할 때는 .ico, .png 파일 등등을 사용 가능합니다. 실행파일 아이콘이 되는 것이므로 배경은 투명한 배경의 아이콘이 좋습니다.

위의 몇가지 옵션들을 사용하여 exe 파일을 만든다면, 명령어는 아래와 같습니다.

pyinstaller --noconsole --onefile --icon=파일경로\아이콘.png/ico 파일경로\파이썬파일.py

예를 들어, minigame.py라는 파이썬 파일이 있고, star.png라는 아이콘 파일이 있으면 아래와 같이 작성하면 됩니다.

pyinstaller --noconsole --onefile --icon=star.png minigame.py

물론, 파이썬 파일과 png 파일은 해당 터미널 위치에 두 파일이 모두 있어야 합니다.

그러면 dist 파일 안에 exe파일이 만들어집니다.

 

이미지, 소리파일 등등을 .exe파일에 포함하는 방법

저는 전에 제가 pygame으로 만든 미니게임을 exe파일로 만들어 보도록 하겠습니다.

다만, 게임은 보통 이미지 파일과 효과음 등의 소리파일이 포함되어 있습니다.

저는 이 모든 파일을 하나의 exe파일에 포함을 하고 싶기 때문에 추가로 설정을 해주고 .exe파일을 만들어 보도록 하겠습니다.

1. 파이썬 파일(.py)에 설정값 넣어주기

exe파일로 만들려는. py파일 스크립트 맨 위에 아래와 같이 코드를 추가해줍니다.

import sys,os

if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'):
    os.chdir(sys._MEIPASS)

2. pyinstaller로 --add-data 파일/폴더 옵션 설정하여 exe파일 만들기 

만약 추가할 이미지 등의 파일이 한가지라면 --add-data 파일경로/파일 이렇게 끝에 옵션을 추가해 주면 됩니다.

저의 경우는 resource라는 폴더 안에 이미지, 소리 등의 파일이 다 들어있어서 폴더를 추가해 주도록 하겠습니다.

제 터미널 위치에 있는 파일 예시는 아래와 같습니다.

pygame/
|--- minigame.py
|--- resources/
     |--- enemy.jpg
     |--- player.jpg
     |--- game_over.wav
     |--- background.wav
     |--- babychick.ico

 

터미널이 위치한 pygame 폴더 안에

minigame.py라는 파이썬 게임파일과,

resources라는 게임을 동작하기 위해 필요한 이미지, 소리파일들이 있습니다.

저는 그리고 exe 아이콘으로 resources 폴더 안에 있는 babychick.ico라는 이미지를 사용하도록 하겠습니다.

(※참고: 아이콘 이미지는 여기에서 찾아서 다운받을 수 있습니다.)

이렇게 exe파일을 만들기 위한 명령어는 아래와 같습니다.

pyinstaller --noconsole --onefile --icon=resources\babychick.ico minigame.py --add-data "resources;resources"

--add -data 를 사용하여 resources폴더를 exe에 추가하였습니다.

그러면,

해당 pygame폴더 위치에 build, dist 등의 폴더가 생기며,(build 폴더는 삭제하셔도 exe 실행하는 데 문제가 없습니다.)

우리가 원하는 exe파일은 dist 폴더에 위치해 있습니다.

이 .exe파일만 따로 빼서 다른 사람들에게 보내면

추가로 파이썬을 설치하거나 할 필요 없이 바로 파일실행으로 게임이 실행됩니다:)

결과물

 

참고자료

https://pyinstaller.org/en/stable/index.html

 

PyInstaller Manual — PyInstaller 5.8.0 documentation

PyInstaller bundles a Python application and all its dependencies into a single package. The user can run the packaged app without installing a Python interpreter or any modules. PyInstaller supports Python 3.7 and newer, and correctly bundles many major P

pyinstaller.org

https://api.arcade.academy/en/latest/tutorials/bundling_with_pyinstaller/index.html

 

Bundling a Game with PyInstaller - Python Arcade 2.6.17

Previous GPU Particle Burst

api.arcade.academy

 

마무리

제가 만든 .exe파일은 소리, 이미지 파일을 추가하다보니 용량이 커져서 실행 시작때 조금 느리지만(259MB 정도 됩니다...)

게임은 실행이 잘 되니 좋습니다:)

여러분들도 한번 그동안 만들었던 파이썬 파일로 실행파일 만들어서

친구,가족분들께 보여주면 좋을 것 같습니다.

반응형
반응형

안녕하세요.

이번에는 저번 pygame포스팅에 이어서 인트로와 아웃트로를 추가해 주도록 하겠습니다.

- 인트로: 게임 설명 및 시작, 종료 버튼 추가

- 아웃트로: 게임 스코어 안내 및 다시시작, 종료 버튼 추가

저번에는 따로 함수를 만들지 않았는데 이번에는

intro, game, outro 함수를 각각 만들어 연결해 보도록 하겠습니다.

이번 게시물의 결과물을 아래에서 미리 확인해 보세요:)

Preview

 

게임 기본 설정
import pygame, sys
from pygame.locals import *
import random, time

pygame.init()

# 초당 프레임 설정
FPS = 60
FramePerSec = pygame.time.Clock()

# 색상 세팅(RGB코드)
RED = (255, 0, 0)
ORANGE = (255, 153, 51)
YELLOW = (255, 255, 0)
GREEN = (0, 255, 0)
SEAGREEN = (60, 179, 113)
BLUE = (0, 0, 255)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
VIOLET = (204, 153, 255)
PINK = (255, 153, 153)

GREY = (213,213,213)
LIGHT_GREY = (246,246,246)
LIGHT_BLACK = (76,76,76)
# 게임 진행에 필요한 변수들 설정
SPEED = 5  # 게임 진행 속도
SCORE = 0  # 플레이어 점수

# 폰트 설정
font = pygame.font.SysFont('Tahoma', 60)  # 기본 폰트 및 사이즈 설정(폰트1)
small_font = pygame.font.SysFont('Malgun Gothic', 20,bold=True)  # 작은 사이즈 폰트(폰트2)
middle_font = pygame.font.SysFont('Malgun Gothic', 40) # 중간 사이즈 폰트(폰트3)
game_over = font.render("GG", True, BLACK)  # 게임 종료시 문구

# 게임 배경화면
background = pygame.image.load('resources/background1.jpg')  # 배경화면 사진 로드

# 게임 화면 생성 및 설정
display_width = 640
display_height = 440
GameDisplay = pygame.display.set_mode((display_width,display_height))
GameDisplay.fill(PINK)
pygame.display.set_caption("Mini Game")

#점수 reset함수
def reset():
    global SCORE
    SCORE = 0
    return SCORE

 

Button 함수 만들기

Intro,outro에 사용할 버튼을 간단하게 만들기 위해 버튼을 만드는 함수를 하나 추가해 줍니다.

이 버튼 함수는 버튼 영역 안에 마우스 포인터가 들어가면 색이 바뀌고 클릭 시 True값을 return 합니다.

더 자세히 설명하자면 아래와 같습니다.

button(버튼안에 들어갈 메세지, x좌표,y좌표, 도형의가로길이,도형의세로길이,도형색, 포인터가 도형위에 위치시 변하는 색, action=True(클릭했을 때 이벤트 활성화), 버튼글씨색 설정 )

#버튼 생성 함수
def button(msg,x,y,w,h,ic,ac,action=None,fcolor=BLACK):
    mouse = pygame.mouse.get_pos()
    click = pygame.mouse.get_pressed()
    #print(click)
    if x+w > mouse[0] > x and y+h > mouse[1] > y:
        pygame.draw.ellipse(GameDisplay, ac,(x,y,w,h))

        if click[0] == 1 and action != None:
            return True
    else:
        pygame.draw.ellipse(GameDisplay, ic,(x,y,w,h))

    textSurf = middle_font.render(msg,True,fcolor)
    textRect = textSurf.get_rect()
    textRect.center = ( (x+(w/2)), (y+(h/2)) )
    GameDisplay.blit(textSurf, textRect)

 

Intro 만들기

게임 설명 텍스트를 위치시켜주고,

start, quit 버튼을 만들어서

start를 누를 시 게임을 시작하고, quit을 누르면 창이 닫히도록 game_intro 함수를 만들어 주었습니다.

# 시작(intro) 화면
def game_intro():
    intro = True

    while intro:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        # 배경화면 사진 게임창에 불러오기(사진, 위치)
        GameDisplay.blit(background, (0, 0)) #TODO
        # 텍스트 생성 및 배치하기
        large_Text = pygame.font.SysFont('Tahoma', 100)
        Text1,Text1Rect = text_objects("How to Play",large_Text)
        Text2,Text2Rect = text_objects("Use ← , → to avoid bombs!",middle_font)
        Text3,Text3Rect = text_objects("방향키 ← , →를 사용하여 폭탄을 피하세요!",small_font)
        Text1Rect.center = ((display_width/2),(display_height/4.5))
        Text2Rect.center = ((display_width/2),(display_height/2.5))
        Text3Rect.center = ((display_width/2),(display_height/2))
        GameDisplay.blit(Text1, Text1Rect)
        GameDisplay.blit(Text2,Text2Rect)
        GameDisplay.blit(Text3,Text3Rect)
        #start,quit버튼
        introBtn1 = button("START",display_width/6,display_height/1.7,200,100,BLACK,BLUE,action=True,fcolor=YELLOW)
        introBtn2 = button("QUIT",display_width/2,display_height/1.7,200,100,BLACK,RED,action=True,fcolor=YELLOW) 
        #버튼을 눌렀을 때
        if introBtn1 == True:
            return game()
        if introBtn2 ==True:
            pygame.quit()
            quit()
        pygame.display.update()
        FramePerSec.tick(FPS)

 

게임에서 동작할 class 만들기

게임에서 사용할 플레이어 및 적 개체 class를 저번 처럼만들어 줍니다.

## 게임 내에서 동작할 클래스 설정 ##

## 플레이어에게 적용할 클래스
class Player(pygame.sprite.Sprite):
    # 플레이어 이미지 로딩 및 설정 함수
    def __init__(self):
        super().__init__()
        # 플레이어 사진 불러오기
        self.image = pygame.image.load('resources/chick.png')
        # 이미지 크기의 직사각형 모양 불러오기
        self.rect = self.image.get_rect()
        # rec 크기 축소(충돌판정 이미지에 맞추기 위함)
        self.rect = self.rect.inflate(-20,-20)
        # 이미지 시작 위치 설정
        self.rect.center = (540, 390)

    # 플레이어 키보드움직임 설정 함수
    def move(self):
        prssdKeys = pygame.key.get_pressed()
        # 왼쪽 방향키를 누르면 5만큼 왼쪽 이동
        if self.rect.left > 0:
            if prssdKeys[K_LEFT]:
                self.rect.move_ip(-5, 0)
                position_p = self.rect.center
                return position_p
        # 오른쪽을 누르면 5만큼 오른쪽으로 이동
        if self.rect.right < 640:
            if prssdKeys[K_RIGHT]:
                self.rect.move_ip(5, 0)
                position_p = self.rect.center
                return position_p


## 적에게 적용할 클래스
class Enemy(pygame.sprite.Sprite):

    # 적의 이미지 로딩 및 설정 함수
    def __init__(self):
        super().__init__()
        # 적 사진 불러오기
        self.image = pygame.image.load('resources/boom2.png')
        # 이미지 크기의 직사각형 모양 불러오기
        self.rect = self.image.get_rect()
        # rec 크기 축소(충돌판정 이미지에 맞추기 위함)
        self.rect = self.rect.inflate(-20,-20)
        # 이미지 시작 위치 설정
        self.rect.center = (random.randint(40, 600), 0)

    # 적의 움직임 설정 함수+ 플레이어 점수 측정
    def move(self):
        global SCORE

        # 적을 10픽셀크기만큼 위에서 아래로 떨어지도록 설정
        self.rect.move_ip(0, SPEED)  # x,y좌표 설정
        # 이미지 가 화면 끝에 있으면(플레이어가 물체를 피하면) 다시 이미지 위치 세팅 + 1점 추가
        if (self.rect.bottom > 440):
            SCORE += 1
            self.rect.top = 0
            self.rect.center = (random.randint(30, 610), 0)
        return self.rect.center
게임 만들기

이제 위의 클래스를 사용하여 폭탄 피하기 게임을 만들어 줍니다.

게임 종료 시 outro화면으로 넘어갈 수 있도록 설정하는 것도 잊지 말고 넣어 줍니다.

###### 게임 설정 ########
# 플레이어 및 적 개체 생성
def game(speed = SPEED):

    P1 = Player()

    E1 = Enemy()

    # Sprites Groups 생성하기
    # 게임 물체들을 그룹화 하여 그룹별로 접근하여 설정 시 용이하게 만들기
    # 적(enemy) 객체 그룹화하기
    Enemies = pygame.sprite.Group()
    Enemies.add(E1)
    # 전체 그룹을 묶기
    All_groups = pygame.sprite.Group()
    All_groups.add(P1)
    All_groups.add(E1)

    # 적 개체 1초(1000ms)마다 새로 생기는 이벤트 생성
    increaseSpeed = pygame.USEREVENT + 1
    pygame.time.set_timer(increaseSpeed, 1000)

    # 게임 BGM 설정
    bgm = pygame.mixer.Sound('resources/backgroundMusic.mp3')
    bgm.play()
    ## 게임 루프 설정 ##
    # 게임 종료되기 전까지 실행되는 루프(이벤트) 설정
    while True:
        for event in pygame.event.get():
            # type increaseSpeed이면 속도 증가하여 어렵게 만듬(적 물체 이벤트)
            if event.type == increaseSpeed:
                speed += 0.5
            # 이벤트가 종료되면 게임도 종료시킴
            if event.type == QUIT:
                pygame.quit()
                sys.exit()

        # 배경화면 사진 게임창에 불러오기(사진, 위치)
        GameDisplay.blit(background, (0, 0))
        # 하단부에 위치할 스코어 점수(적을 피할때마다 +1점 증가)
        scores = small_font.render("Score: " + str(SCORE), True, BLACK)
        GameDisplay.blit(scores, (10, 400))

        # group1 = '<Player Sprite(in 1 groups)>'
        # group2 = '<Enemy Sprite(in 2 groups)>'

        # 게임 내 물체 움직임 생성
        for i in All_groups:
            GameDisplay.blit(i.image, i.rect)
            i.move()
            if str(i) == '<Player Sprite(in 1 groups)>':
                player_pos = i
            else:
                enemy_pos = i

        # <Player Sprite(in 1 groups)>
        # 플레이어 충돌 판정(게임종료)시
        if pygame.sprite.spritecollideany(P1, Enemies):
            for i in All_groups:
                i.kill()
            # 물체 이미지 변경(충돌후 변경되는 이미지)
            # 플레이어
            GameDisplay.blit(background, (0, 0))
            image0 = pygame.image.load('resources/chickbommed.png')
            image0.get_rect()
            GameDisplay.blit(image0, player_pos)

            # 폭탄
            image1 = pygame.image.load('resources/boomm.png')
            image1.get_rect()
            GameDisplay.blit(image1, enemy_pos)
            pygame.display.update()

            # 배경음악 멈춤
            bgm.stop()
            # 적과 충돌시 효과음 추가
            pygame.mixer.Sound('resources/BOOM.WAV').play()
            time.sleep(0.5)
            # 게임오버화면 설정
            pygame.mixer.Sound('resources/gameover.mp3').play()
            pygame.display.update()
            game_outro()

        pygame.display.update()
        # 초당 프레임 설정
        FramePerSec.tick(FPS)

 

Outro 만들기

게임 종료 화면을 만들어 줍니다.

게임 점수를 배치하고 버튼을 배치하여,

다시 플레이하고 싶은 사람은 score 리셋 후 retry를, 종료하고 싶은 사람은 quit을 눌러 창을 닫을 수 있도록 설정합니다.

## 게임오버 페이지
def game_outro():
    outro = True

    while outro:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        GameDisplay.blit(background, (0, 0))
        final_scores = font.render("Your Score: " + str(SCORE), True, BLACK)
        Music = small_font.render("Music: www.bensound.com",True,BLACK)
        Photos = small_font.render("Photos: pixabay, pngwing",True,BLACK)
        Madeby = small_font.render("Made by wonhwa.tistory.com",True,BLACK)
        GameDisplay.blit(final_scores, (150, 100))
        GameDisplay.blit(game_over, (280, 200))
        GameDisplay.blit(Music,(10,400))
        GameDisplay.blit(Photos,(10,380))
        GameDisplay.blit(Madeby,(350,400))
        #retry,quit버튼
        outroBtn1 = button("RETRY",display_width/6,display_height/1.7,200,100,BLACK,BLUE,action=True,fcolor=YELLOW)
        outroBtn2 = button("QUIT",display_width/2,display_height/1.7,200,100,BLACK,RED,action=True,fcolor=YELLOW)
        #time.sleep(1)
        #pygame.display.update()
        #time.sleep(5) 
        #TODO: 버튼 누르면 동작
        if outroBtn1 == True:
            reset()
            game()
        if outroBtn2 ==True:
            pygame.quit()
            sys.exit()
        pygame.display.update()
        FramePerSec.tick(FPS)

 

게임 시작!

이제 만들어둔 함수를 호출하여 게임을 시작할 수 있습니다.

#####게임 시작#####
game_intro()

 

게임 파일

게임 파이썬 파일을 .exe파일로 만들어 보았습니다.(용량이 259MB로 꽤 큽니다..)

해보고 싶은 분들은 다운받아 실행해보시길 바랍니다 :)

https://drive.google.com/file/d/1fZGR-vbcTgAvsYqhsIh5lmnWSORJ0I0a/view?usp=sharing 

 

minigame.exe

 

drive.google.com

.py를 .exe로 만드는 방법은 아래의 링크를 참고해 주세요.

https://wonhwa.tistory.com/66

 

[python] pyinstaller로 이미지,소리파일이 포함된 .exe파일 만들기(feat.pygame)

안녕하세요. 그동안 python으로 여러 프로그램을 만들어 보았는데, 그걸 다른 사람에게도 보여주고 싶을 때는 1. python 설치 2. .py 파일 실행 이렇게 번거로운 과정이 필요할 것입니다. 하지만 그동

wonhwa.tistory.com

 

전체 코드

https://github.com/ElenaLim/Pygame/blob/main/minigame_ver1.1.py

 

GitHub - ElenaLim/Pygame: Minigame using Pygame

Minigame using Pygame. Contribute to ElenaLim/Pygame development by creating an account on GitHub.

github.com

참고자료

https://wonhwa.tistory.com/45

 

[python/Game] 파이썬으로 게임만들기(2) - 미니게임

이번 포스팅에서는 미니 게임을 pygame을 사용하여 만들어 보도록 하겠습니다. preview 이 게임은 병아리가 폭탄을 피하고 부딪히면 게임이 종료되는 미니게임 입니다. 게임 구성 1. 게임 화면 설정

wonhwa.tistory.com

https://pythonprogramming.net/pygame-button-function/

 

Python Programming Tutorials

PyGame Progress: 0% --> PyGame Buttons, part 4, creating a general PyGame button function Now that we've got some fancy code coming along, it's time to move all of this to a function, so that we can use this dynamically to create other buttons, rather than

pythonprogramming.net

 

마무리

그동안 저번에 만든 미니게임에 인트로,아웃트로를 넣고 싶었는데 드디어 완성할 수 있었네요.

exe파일도 올려두었으니 한번 씩 심심할 때 해보시면 좋을 것 같습니다 ㅎㅎ

반응형
반응형

안녕하세요.

python을 하시는 분들이라면 pandas를 자주 사용하실텐데요,

이 때 , 만들어 둔 csv파일을 to_csv로 저장을 할 때

인코딩 설정을 'utf-8'로 하는 경우가 있습니다.

IDE로 작업 할 땐 아래처럼 한글이 잘 보였는데

실제 저장된 파일을 열어보면,

한글이 깨져 있는 것을 확인할 수 있습니다.

이렇게 되면 파일만 있을 때 어떤 정보가 있는지 확인이 어렵습니다.

그럴 때는 pandas로 csv를 저장 시 인코딩을

utf-8 대신 'utf-8-sig'를 사용하면 한글깨짐을 방지할 수 있습니다!

이렇게 'utf-8-sig' 를 사용하면 저장한 파일을 열어도 한글이 깨지지 않고 잘 보입니다 :)

 

반응형
반응형

Selenium을 사용할 때 드라이버를 다운 받아야 하는데,

크롬 브라우저 사용 시 드라이버를 현재 본인의 크롬 브라우저 버전에 맞춰 다운을 받아줘야 합니다.

예를 들어 한 달 전에 브라우저 1.0 버전을 쓰고 있으면 드라이버도 1.0을 써야 하고,

이후 브라우저를 업데이트 했다면 기존의 드라이버도 역시 해당 버전을 다시 설치해 주어야 합니다.

 

이렇게 매번 selenium 사용시마다 다운받고 설치하는 작업이 번거로운데,

webdriver_manager을 사용하면 드라이버를 직접 다운받지 않고도 자동 설치되며

selenium 이 오류 없이 실행됩니다.

 

라이브러리 설치
pip install webdriver-manager

 

코드
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

# 크롬 드라이버 설치
driver = webdriver.Chrome(ChromeDriverManager().install())

#페이지 불러오기
driver.get('사이트주소')

+ 추가(24.01.27)

요즘은 최신버전으로 크롬업데이트후 selenium을 설치해주시면 드라이버 설치없이도 바로 실행가능합니다.

꼭 크롬 브라우저가 최신버전으로 업데이트되어있는지 확인해주세요.

이미 selenium을 설치한 경우, 최신버전 크롬으로 업데이트후

pip uninstall selenium 으로 기존 셀레니움 삭제 후

재설치 해주시면 실행 됩니다.

from selenium import webdriver

# 크롬 드라이버 설치
driver = webdriver.Chrome()

#페이지 불러오기
driver.get('사이트주소')

+ 위의 방법 사용 중 오류가 나타날 경우

seleniumbase 설치 
pip install seleniumbase
driver 설정
from seleniumbase import Driver
driver = Driver(browser="chrome")

driver.get('사이트주소')

 

유용하게 사용하시길 바랍니다.

반응형
반응형

안녕하세요!

오늘은 Pandas의 apply 메서드를 사용하는 방법을 알아보도록 하겠습니다.

 

종종 pandas로 csv 파일을 열어 dataframe을 만들 때, 

각 행을 계산한다던가, 열을 계산하여야 할 때가 있습니다.

이때 pandas 의 apply 메서드를 사용하면 만들어 둔 함수를 간편하게 적용하여 계산이 가능합니다.

 

데이터 준비

데이터는 kaggle의 Lemonade-Orange-stand를 사용해 보겠습니다.

https://www.kaggle.com/datasets/adisak/lemonade-stand

 

Lemonade-Orange-stand

Lamonade and Orange Stand sales

www.kaggle.com

이 데이터는 각 날짜의 레몬, 오렌지 에이드 판매량을 보여주는 데이터셋입니다.

링크를 들어가서 Lemonade2016-2.csv 파일을 다운받아 줍니다.

그 후 csv파일을 아래와 같이 열어 줍니다.

import pandas as pd
df = pd.read_csv('Lemonade2016-2.csv')
df


각 컬럼의 의미는 다음과 같습니다.

Date: 날짜

Location: 판매장소(공원/해변가)

Lemon: 레몬에이드 판매량(잔)

Orange: 오렌지에이드 판매량(잔)

Temperature: 기온(화씨/ºF)

Leaflets: 배포한 전단지 수

Price: 가격($)

 

Series에서 apply 적용하기 - 1개의 인자를 전달받는 함수
현재 df에 있는 temperature은 화씨온도로 한국에서 쓰는 섭씨온도랑 단위가 다릅니다.
때문에 온도를 이해하기 쉽게 섭씨 온도로 바꿔주는 작업을 해보도록 하겠습니다.
 
화씨온도에서 섭씨온도로 변환하는 식은 아래와 같습니다.

°C = (°F−32)×5/9

이것을 'to_C'라는 함수로 만들어 보겠습니다.
#화씨->섭씨 함수
# (temperature - 32) * 5 / 9
def to_C(x):
    C = (x - 32) * 5 / 9
    # 소수 셋째자리에서 반올림
    C = round(C,2)
    return C

그리고 df에서 따로 날짜컬럼만 빼어서 apply 함수 적용 후 새로운 df열에 할당해 주도록 하겠습니다.

# 기온(temperature)을 섭씨(ºC)로 변환
temp = df['Temperature']
# apply 함수 적용 후 새로운 열에 섭씨온도 추가해 주기
df['temp_C'] = temp.apply(to_C)
df
 
오른쪽 맨 끝열에 섭씨 온도가 잘 추가되었습니다.
 
2개의 인자를 전달받는 함수 - 25센트짜리 레몬에이드 판매액을 구하기
이번에는 각 날짜의 레몬에이드 판매액이 얼마인지 apply를 사용해 구해보도록 하겠습니다.
레몬에이드 판매액은
 
레몬에이드 판매 수 x 가격
 
으로 구할 수 있습니다.
이번에는 레몬에이드가 25센트일때의 그날의 판매액을 구하는 것이므로
먼저 레몬에이드가 25센트인 날만 필터링하여줍니다.
# price가 0.25인것만 필터링
cent_25 = df[df['Price'] == 0.25]
cent_25

 이렇게 25센트인 날만 추출이 완료되었습니다.

 

 
그 후, 판매액을 구하는 함수를 만들어 apply로 적용해 줍니다.
 
apply 적용 시 Lemon열에서 적용하여 줍니다. price는 0.25로 모든 열이 같으므로
price 인자를 전달할 때 price=0.25로 고정하여 줍니다.
#판매액 을 구하는 함수
def lemon_money(x, price):
    total = x * price
    return total
cent_25['Lemon'].apply(lemon_money,price=0.25)
이렇게 판매액 계산이 완료되었습니다.
 
Dataframe에서 apply 적용하기 - 3개의 인자를 입력받아 계산하는 경우
이번에는 레몬 에이드와 오렌지 에이드 판매량을 합쳐 각 날짜의 총 판매액을 구해보도록 하겠습니다.
이것을 함수로 작성한다면 일반적인 경우는 아래와 같이 작성할 것 입니다.
 
(레몬에이드 판매량 +오렌지에이드 판매량) *가격
def total(x,y,price):
    total_money = (x+y)*price
    return total_money
하지만 dataframe에 apply를 적용할 때는 행 단위 또는 열 단위로만 값을 입력받기 때문에,
위의 함수식을 한개의 인자를 받는 함수로 바꾸어야 합니다.
그 후 이 함수식 안에서 3개의 인자를 생성하는 방향으로 함수를 수정하겠습니다.
 
이 때, df에서 사용하는 값이 각 행의 'Lemon', 'Orange', 'Price' 컬럼 이므로 
이를 각각 함수 내에서 x,y,price라는 변수 생성후 열 번호로 할당을 해주도록 하겠습니다.
 
각 컬럼의 위치와 인덱스를 아래와 같이 확인하여 줍니다.
#컬럼확인
df.columns​

#컬럼 번호 확인
for itr,i in enumerate(df.columns):
    print(itr,' : ',i)
그 후 함수를 한 개의 인자값을 받는 함수로 수정하여 줍니다.
# 1개의 인자값을 가지는 함수로 변경
# x=레몬에이드,y=오렌지에이드,price=가격 각각 열 위치로 변수 할당
def total(col):
    x = col[2] #Lemon
    y = col[3] #Orange
    price = col[6] #Price
    total_money = (x+y)*price
    return total_money
마지막으로, apply를 사용하여 해당 함수를 적용하여 줍니다.
각 열을 인자값으로 사용하므로 axis=1로 설정해 줍니다.(axis=0은 행방향)
#df에 적용하여 리턴값 새 열에 할당
# 열 기준이므로 axis = 1
df['total'] = df.apply(total,axis=1)
df​
이렇게 total 열에 총 판매액 계산이 잘 되었습니다.

 

전체 코드
import pandas as pd

df = pd.read_csv('Lemonade2016-2.csv')

# 기온(temperature)을 섭씨(ºC)로 변환
temp = df['Temperature']

#화씨->섭씨 함수
# (temperature - 32) * 5 / 9
def to_C(x):
    C = (x - 32) * 5 / 9
    # 소수 셋째자리에서 반올림
    C = round(C,2)
    return C
    
# apply 함수 적용 후 새로운 열에 섭씨온도 추가해 주기
df['temp_C'] = temp.apply(to_C)

# price가 0.25인것만 필터링
cent_25 = df[df['Price'] == 0.25]

#판매액 을 구하는 함수
def lemon_money(x, price):
    total = x * price
    return total
cent_25['Lemon'].apply(lemon_money,price=0.25)

#컬럼확인
df.columns
#컬럼 번호 확인
for itr,i in enumerate(df.columns):
    print(itr,' : ',i)

# 1개의 인자값을 가지는 함수로 변경
# x=레몬에이드,y=오렌지에이드,price=가격 각각 열 위치로 변수 할당
def total(col):
    x = col[2] #Lemon
    y = col[3] #Orange
    price = col[6] #Price
    total_money = (x+y)*price
    return total_money
    
#df에 적용하여 리턴값 새 열에 할당
# 열 기준이므로 axis = 1
df['total'] = df.apply(total,axis=1)
df
코드파일

apply_practice.ipynb
0.06MB

 

참고자료

Do it! 데이터 분석을 위한 판다스 입문

 

마무리

apply는 활용도가 높은 메서드 입니다. 유용히 사용하셨으면 좋겠습니다 ㅎㅎ

 

+ Blogspot 블로그도 개설하였습니다!

종종 방문해 주시면 좋겠습니다 ㅎㅎ

https://wonhwa1.blogspot.com/2022/10/python-pandas-apply.html

 

[python] pandas Apply를 사용하여 함수를 한번에 적용하기

Apply 종종 pandas로 csv 파일을 열어 dataframe을 만들 때,  각 행을 계산한다던가, 열을 계산하여야 할 때가 있습니다. 이때 pandas 의 apply 메서드를 사용하면 만들어 둔 함수를 간편하게 적용하여 계산

wonhwa1.blogspot.com

 

반응형
반응형

안녕하세요.

저번 포스팅에 이어서 pandas를 활용하여 날짜&시간 데이터를 다루는 방법 2편 시작하도록 하겠습니다!

 

데이터 준비

이번에 사용할 데이터는 국가 별 기대수명 데이터 입니다!

15개의 각 나라에 대한 년도별 기대수명이 있는 데이터 입니다.

Kaggle에서 다운받을 수 있으며 아래의 링크에서 찾을 수 있습니다.

https://www.kaggle.com/datasets/brendan45774/countries-life-expectancy

 

Countries Life Expectancy

Countries Life Expectancy

www.kaggle.com

Download 버튼을 눌러서 다운받으실 수 있습니다 ㅎㅎ

 

CSV 파일 불러오기 및 데이터 확인
import pandas as pd
df = pd.read_csv("Life expectancy.csv")
df

데이터를 확인해 보면 3253행  x3열 이며 각 컬럼은 나라(Entity), 년도(Year), 기대수명(Life expectancy)을 의미합니다.

여기서 시간데이터인 Year 컬럼을 to_datetime으로 형변환을 해 주도록 하겠습니다.

 

날짜형 데이터로 변환

저번 1편에서 확인했듯이 pd.to_datetime를 사용하여 형변환을 해주고 데이터 타입을 확인하여 보면 아래와 같습니다.

# year을 데이터형으로 변환
df['Year'] = pd.to_datetime(df['Year'],format = '%Y')
df.dtypes

의도했던 대로 Year 컬럼이 datetime형으로 바뀌었습니다.

데이터도 다시 확인하여 보면 날짜형으로 바뀌었음을 알 수 있습니다.

 

날짜, 시간데이터의 증감 - timedelta

이 시간데이터를 가지고 날짜, 시간데이터의 증감을 해 보도록 하겠습니다.

datetime의 timedelta를 이용하면 날짜별, 시간별로 데이터를 더할 수 있습니다.

# 일자 더하기
날짜데이터 + datetime.timedelta(days = 더할 일수)

# 시간 더하기
날짜데이터 + datetime.timedelta(hours = 더할 시간)

# 분 더하기
날짜데이터 + datetime.timedelta(minutes = 더할 분)

# 초 더하기
날짜데이터 + datetime.timedelta(seconds = 더할 초)

아래 예제에서는 각각 1일, 1시간, 1분, 1초를 Year 열에 더해 보았습니다.

import datetime
# 시간 더하기
#일 
addDay = df['Year']+ datetime.timedelta(days=1)
#시
addHour = df['Year']+ datetime.timedelta(hours=1)
#분
addMinute = df['Year']+ datetime.timedelta(minutes=1)
#초
addSecond = df['Year']+ datetime.timedelta(seconds=1)

각각 데이터가 잘 더해진 것을 확인할 수 있습니다.

Pivot_table을 사용하여 행, 열 바꾸기

이 데이터를 보면 나라별로 데이터가 나누어져 있습니다. 

이 데이터를 Year을 인덱스로 하여 행으로 바꿔주고 나라를 컬럼으로, 기대수명을 값으로 하여 

데이터 프레임을 만들어 보도록 하겠습니다.

이 때 pivot_table을 사용하여 값을 바꿀 수 있습니다.

pivot_table에 대한 자세한 내용은 전에 포스팅을 참고해 주세요.

https://wonhwa.tistory.com/27?category=996516 

 

[python] pandas(판다스) - groupby, pivot_table, melt

Pandas는 데이터 분석을 할 때 필수적으로 사용하는 파이썬 라이브러리입니다. 오늘은 유용하게 쓰일 수 있는 판다스의 메소드 몇 가지를 간단히 알아보도록 하겠습니다. Groupby 그룹바이 pandas.grou

wonhwa.tistory.com

# 피벗으로 행렬 전환
# index = Year
# columns = Entity
# values = Life expectancy
df_pivot = df.pivot_table(
                index='Year',
                columns='Entity',
                values='Life expectancy')
df_pivot

이렇게 원하는 모양의 데이터프레임이 만들어졌습니다 :)

이제 이 csv 파일을 저장 후 다음 예제는 이 파일을 사용해 보도록 하겠습니다.

# 피벗한 테이블 csv 저장
df_pivot.to_csv('LifeExp_pivot.csv')

df_pivot = pd.read_csv('LifeExp_pivot.csv')

 

날짜 데이터를 분류하기

이 데이터는 1800년부터 2016년도까지의 총 217년의 데이터가 있는데 

각 세기별로 나누어 데이터를 확인해 보도록 하겠습니다.

1세기 = 100년 이며

이데이터는 18C~21C까지의 데이터 이므로 컬럼을 하나 만들어 각 세기를 입력해 주도록 하겠습니다.

년도를 세기별로 변환하는 방법으로

1. 함수를 만들기

2. apply함수를 이용한 계산 및 Categorical을 이용하여 범주형으로 입력

이렇게 2가지를 거쳐 쉽게 분류할 수 있습니다.

먼저 아래와 같이 함수를 만들어 각 년도별 해당 세기를 return 하는 함수를 만들어 줍니다.

예를 들어 19C는 1801년~1900년 까지 입니다.

if , elif, else 를 이용하여 만들 수 있습니다.

# 세기별로 나누기
# 18,19,20,21세기
#예) 19세기: 1801-01-01 ~ 1900-12-31

# 년도를 세기별로 변환하는 함수
def to_century(year_num):
    century = '21C'
    if year_num == 1800:
        century = '18C'
    elif 1801 <= year_num <= 1900:
        century = '19C'
    elif 1901 <= year_num <= 2000:
        century = '20C'
    return century

그 뒤 Year을 기준으로 세기가 정해지기 때문에 Year컬럼을 datetime형으로 바꿔준 후,

dt를 사용하여 year에 접근하여 그 값에대해 apply로 위에서 만든 to_century 함수를 적용해 줍니다.

그 값은 'Century'라는 컬럼에 새로 할당해 주면 완성됩니다.

#Year을 datetime64[ns]형변환 하기
df_pivot['Year'] = pd.to_datetime(df_pivot['Year'],format='%Y-%m-%d')
#세기별로 변환하기
df_pivot['Century'] = pd.Categorical(
                        df_pivot['Year'].dt.year.apply(to_century),
                        categories=['18C','19C','20C','21C'])
df_pivot

맨 끝에 Century 열이 추가 된 것을 확인할 수 있습니다.

 

시각화

이제 이것을 가지고 세기별 국가들의 기대수명을 확인해 보도록 하겠습니다.

국가는 Austrailia(호주), Brazil(브라질), Canada(캐나다), China(중국), France(프랑스), Germany(독일), India(인도), Italy(이탈리아), Japan(일본), Mexico(멕시코), Russia(러시아), Spain(스페인), Switzerland(스위스), United Kingdom(영국), United States(미국) 이렇게 15개국이 있습니다.

그리고 데이터에서 세기별로 데이터를 나누고 그 데이터를 시각화해주도록 하겠습니다.

데이터는 100년의 데이터가 다 있는 19C, 20C만 해보도록 하겠습니다.

matplotlib을 사용하여 그래프를 그리고, 국가 수 가 많으므로 범례를 추가해 주고 색도 각자 다른 색으로 추가해 주겠습니다.

matplotlib에서 제공하는 컬러맵은 아래의 링크에서 확인이 가능합니다.

https://matplotlib.org/stable/tutorials/colors/colormaps.html

 

Choosing Colormaps in Matplotlib — Matplotlib 3.6.0 documentation

Note Click here to download the full example code Choosing Colormaps in Matplotlib Matplotlib has a number of built-in colormaps accessible via matplotlib.colormaps. There are also external libraries that have many extra colormaps, which can be viewed in t

matplotlib.org

import matplotlib.pyplot as plt
import numpy as np
#19C 수명 변화 시각화
Century19 = df_pivot[df_pivot['Century'] == '19C']

fig1 = plt.figure(figsize=(15,15))
ax1 = fig1.add_subplot(111)
ax1.plot(Century19['Year'], Century19.iloc[:,1:16])

colormap = plt.cm.tab20b #컬러맵  
colors = [colormap(i) for i in np.linspace(0, 1,len(ax1.lines))]

for i,j in enumerate(ax1.lines):
    j.set_color(colors[i])

plt.legend(Century19.columns[1:16])
plt.show()

이 각 나라별로 수명 변동이 있는데 그 중에서 러시아의 수명이 눈에 띕니다.

1848년정도에 기대수명이 18세 정도까지 떨어졌는데 

이때 왜 그런지 찾아보니

1848때 헝가리 혁명이 있었고, 그 때 러시아가 많은 사람을 파병했다고 합니다. 

이렇게 기대수명이 급감한 년도를 살펴보면 역사적인 사건들과 관련있는 것을 확인할 수 있습니다.

이번에는 20C의 기대수명을 시각화 해보도록 하겠습니다.

#20C 수명 변화 시각화
Century20 = df_pivot[df_pivot['Century'] == '20C']

fig2 = plt.figure(figsize=(15,15))
ax2 = fig2.add_subplot(111)
ax2.plot(Century20['Year'], Century20.iloc[:,1:16])

colormap = plt.cm.tab20b #컬러맵  
colors = [colormap(i) for i in np.linspace(0, 1,len(ax2.lines))]

for i,j in enumerate(ax2.lines):
    j.set_color(colors[i])

plt.legend(Century20.columns[1:16])
plt.show()

20세기는 1,2차 세계대전이 있었던 만큼 그 시기에 대부분 국가의 기대수명이 낮음을 확인할 수 있습니다.

1914~1918년도에는 제 1차 세계대전이, 1939 ~ 1945년 까지는 2차 세계대전이 있었고 그 시기 기대수명이 확 낮아졌음을 확인할 수 있습니다.

여기서 특이한 점은 인도는 특히 1918년도에 기대수명이 8세정도까지 되지않아

한 번 알아보았는데 이시기에 인도가 스페인독감으로 가장 많은 사상자를 내었다고 합니다. 1천7백만명의 사람이 사망했다고 합니다. 이시기에 다른 국가들로 독감으로 인해 많은 사망자가 나왔음을 확인할 수 있습니다.

 

전체 코드

TimeSeriesData2.ipynb
0.51MB

참고자료

1. Do it 데이터 분석을 위한 판다스 입문

2. 데이터 전처리 대전

 

마무리

이번에는 기대수명을 가지고 시간데이터 증감 하는 방법 및 분류 하는 방법도 알아보고

간단한 분석도 해보았는데 저도 하면서 재밌었네요ㅎㅎ

이렇게 역사 공부도 하고 기억에도 잘 남을 것 같습니다.

그리고 다음에 좋은 시계열데이터 예제가 있다면 관련하여 포스팅 하도록 하겠습니다.

반응형
반응형

안녕하세요.
분석할 csv 파일을 읽어올 때 시계열 데이터도 들어있는 경우도 많을 텐데요,
이때 전처리나 기본 분석을 할 때 도움이 될 수 있도록
날짜 및 시간 데이터를 pandas에서 다루는 방법에 대해 포스팅 하려고 합니다.
그럼 시작하겠습니다!

데이터 준비

데이터로는 공공데이터 API를 통해 생성한 코로나 확진자 관련 csv 파일을 준비해 보았습니다.
데이터 파일 만드는 방법은 아래의 링크를 참고해 주세요 :)
https://wonhwa.tistory.com/16?category=996518

[python] 공공데이터 OPEN API의 xml 을 DataFrame으로 변환하기(feat. 코로나 확진자 수)

안녕하세요~! 오늘은 공공데이터 openAPI의 xml을 Pandas DataFrame으로 변환하여 보도록 하겠습니다. json에서 DataFrame으로의 변환은 여기를 클릭해서 확인해 주세요 :) step1. 데이터 활용신청하기 공공데

wonhwa.tistory.com


저는 전에 만들어 둔 2020년 01월 20일부터 2022년 02월 23일까지의 시도별 코로나 확진자 현황 파일을 사용하였습니다.

Covid19Korea(200120220223).csv
1.75MB

파일이 필요하신 분은 위에서 다운받아 실습 진행하시면 됩니다!

csv 불러오기 및 데이터 타입 확인하기

그럼 위에서 다운받은 csv파일을 불러와 보도록 하겠습니다.
그리고, dtypes를 사용하여 파일 전체 열에 대해 데이터 타입이 어떻게 설정되어 있는지 확인합니다.

#데이터 불러오기
import pandas as pd
covid_df = pd.read_csv('Covid19Korea(200120220223).csv')
covid_df

14454행 x 14열 을 가진 데이터 프레임이 불러와졌습니다.
데이터 열에 관련해서는 아래를 참고해 주세요.

출처: 공공데이터 API 문서(코로나바이러스감염증_시도발생_현황조회서비스)
#데이터 타입 확인
covid_df.dtypes

데이터 타입을 확인해 보면, createDt(등록일시분초), std_day(기준일시) 등은 날짜형인데도 object로 설정되어있는 것을 확인할 수 있습니다.
(눈으로 볼때는 날짜형으로 보여도 실제 데이터 타입은 다를 수 있으니 항상 사전에 확인해 보시길 바랍니다.)
pandas에서 날짜 계산이나 추출을 위해서는 해당 열을 datetime 형으로 바꿔주어야 올바른 계산이 가능합니다.
때문에 날짜데이터로 형변환을 해 주도록 하겠습니다.

datetime으로 데이터 타입 변경하기

날짜 데이터로 변경할 때
1. to_datetime으로 변경하는 방법

2. parse_dates=[col_idx]
의 2가지 방법으로 변경이 가능합니다.
createDt열을 datetime으로 변경해 보도록 하겠습니다.
아래는 pd.to_datetime을 사용하여 변경하는 방법입니다.

#createDt열 날짜 데이터 타입으로 변경하기
covid_df['createDt'] = pd.to_datetime(covid_df['createDt'])

다음으로는 csv를 불러올 때 parse_dates = [열인덱스]를 사용하여 변경하는 방법입니다.
코로나csv 파일에서 createDt가 0번째 열이므로 [0] 을 입력해 줍니다.
그후 데이터 타입을 출력해 봅니다.

#createDt열 날짜 데이터 타입으로 변경방법 2: parse_dates=[col_idx]사용
covid_df2 = pd.read_csv('Covid19Korea(200120220223).csv', parse_dates=[0])
covid_df2.dtypes

그럼 아까 object였던 createDt열이 datetime으로 변경된 것을 확인할 수 있습니다.
추가로, stdDay도 datetime으로 바꿔보도록 하겠습니다.
다만, stdDay는

위처럼 한글이 섞여 있어 '년','월','일','시'를 제거 후 datetime으로 변경해 주겠습니다.

# stdDay열은 한글이 섞여 있으므로 한글 제거 후 datetime으로 변경
covid_df['stdDay'] = covid_df['stdDay'].replace(['년','월','일','시'],"",regex=True)
covid_df[['stdDay']]

replace를 사용하여 한글을 제거해 주었습니다.
그후 데이터 타입을 변경해 주는데,
pandas에서는 format으로 시간형식 지정자를 입력하여 데이터 타입 변경도 가능합니다.
format='%Y-%m-%d %H:%M'
등으로 지정 가능하며 의미는 아래와 같습니다.

출처:&amp;nbsp;https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior

예시 부분은 영어를 한국어로 번역한 것이라 내용이 어색할 수 있습니다.
때문의 자세한 내용은 아래 링크에서 확인해 주세요.
https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior

datetime — Basic date and time types — Python 3.10.7 documentation

datetime — Basic date and time types Source code: Lib/datetime.py The datetime module supplies classes for manipulating dates and times. While date and time arithmetic is supported, the focus of the implementation is on efficient attribute extraction for

docs.python.org

stdDay는 시간까지의 정보가 있으므로 시간단위까지 format으로 지정해 주겠습니다.

covid_df['stdDay'] = pd.to_datetime(covid_df['stdDay'],format='%Y-%m-%d %H')

이렇게 stdDay열도 datetime으로 변경되었습니다.

세부날짜(년, 월, 일) 추출하기

datetime형의 데이터는 년, 월, 일 등을 각각 뽑아낼 수 있습니다.
해당 날짜 데이터 셀.year을 사용하여 아래처럼 년도를 추출할 수 있습니다.

covid_df['stdDay'][0].year

주의할 점은 df프레임에서 바로 .year을 하면 오류가 나고, covid_df['stdDay'][0] 처럼 개별 데이터로 접근 후 .year을 해야
원하는 정보를 찾을 수 있습니다.
열별로 한번에 데이터를 얻고 싶으면 dt를 사용하여 한번에 추출할 수 있습니다.
예시로,
createDt에서 년, 월, 일을 추출해 각각 새로운 컬럼을 만들어 거기에 저장해 주도록 하겠습니다.

데이터프레임열.dt.year
데이터프레임열.dt.month
데이터프레임열.dt.day

를 사용하여 추출할 수 있습니다.

# 년월일 추출하여 새로운 열로 추가하기
covid_df['Year'],covid_df['Month'],covid_df['Day'] = covid_df['createDt'].dt.year, covid_df['createDt'].dt.month, covid_df['createDt'].dt.day
covid_df

이렇게 끝에 년, 월, 일 3개의 열이 추가가 되었습니다.

날짜의 계산

이번에는 날짜 계산을 해보도록 하겠습니다.
코로나 확진자가 한국에 처음 발생한 날짜를 찾아, 발생일로부터 얼마나 지났는지 계산해 보겠습니다.
코로나 확진자가 최초로 발생한 날은 createDt열의 .min()함수를 사용하여 알 수 있습니다.

# 코로나 최초 발병일로 부터 며칠이 지났는지 계산하기
## 날짜의 계산 ##
# 최초 발생자가 있는 날: 2020년 1월 20일(인천 1명)
covid_df['createDt'].min()

이것을 기준으로 하여 각 행마다 며칠이 지났는지 계산해 보겠습니다.
각 행의 createDt에서 최초 발생일을 빼서 구할 수 있습니다.
outbreak_day = 등록일시 - 최초발생일

# outbreak_day 열을 만들어 발병일로 부터 며칠 지났는지 계산하기
covid_df['outbreak_day'] = covid_df['createDt'] - covid_df['createDt'].min()
covid_df

맨 끝 열에 outbreak_day가 추가되었습니다.

특정 기간의 데이터 추출

이번에는 특정 날짜의 데이터를 loc을 사용하여 추출해 보도록 합시다.

df.loc[df.날짜데이터열이름.dt.(year,month,day) == 해당 (년,월,일)]

위처럼 조건을 지정하여 추출이 가능합니다.
예시로 코로나 데이터의 2021년 데이터만 추출해 보도록 하겠습니다.

## 특정 기간의 데이터 추출
# 2021년 데이터 추출
test1_df = covid_df.loc[covid_df.createDt.dt.year == 2021]
test1_df

두 가지 이상의 조건도 설정 가능합니다.
이때 '&'을 사용하여 and조건을 사용할 수 있습니다.

df.loc[df(조건1) & df( 조건 2 ) ]
#2022년 1월 데이터만 추출(and 조건은 & 로 표시)
test2_df = covid_df.loc[(covid_df.createDt.dt.year == 2021) & (covid_df.createDt.dt.month == 1)]
test2_df

or 조건은 | (Shift+\) 를 사용하여 설정할 수 있습니다.

df.loc[df(조건1) | df( 조건 2 ) ]
#2020년도 또는 2021년도 데이터 추출(or 조건은 | 로 표시)
test3_df = covid_df.loc[(covid_df.createDt.dt.year == 2020) | (covid_df.createDt.dt.year == 2021)]
test3_df

이렇게 데이터를 추출 할 수 있습니다.
다만, 위 사진을 보면 맨 첫행 인덱스가0 이아닌 1026으로 되어 있습니다. 때문에 추후 분석할 때는 인덱스를 0부터 재세팅해주는 과정이 필요합니다.
인덱스 재세팅 방법은 아래 날짜별 값 계산에서 확인해 보도록 하겠습니다.

날짜별 값 계산하기(groupby)

처음 언급했듯이 사용되고 있는 데이터는 2020년부터 2022년 2월까지의 데이터를 담고 있습니다.
그리고 분석 시 년도별 코로나 발생 인원이 몇명인지 알고 싶을 때 groupby를 사용하여 계산을 해 보겠습니다.
우선, 데이터를 보면 시도 데이터 뿐만이 아니라 합계, 검역 같은 데이터 행도 있습니다.
여기서 전체 발생인원을 파악하여야 하니까
'합계' 행만 추출하여 계산하도록 하겠습니다.
우선 원본 df에서 gubun이 '합계'인 행만 추출해 줍니다.

# groupby를 사용하여 년도별 코로나 확진자 수 구하기
# '합계' 를 기준으로 하여 전국 년도별 코로나 확진자 수 구하기
#1. gubun 이 합계인 행만 추출하기
total_df = covid_df.loc[covid_df['gubun']=='합계']
total_df

이렇게 766행이 선택되었습니다.
그런데, 맨 첫 행이 0이 아니라 18 입니다. 때문에 인덱스를 0부터 다시 설정해 줍니다.

# 2. index 재세팅하기
new_idx = [i for i in range(len(total_df))]
total_df.index = new_idx
total_df

그럼 0부터 765까지 전체 행의 인덱스가 잘 정리되었습니다.
그 후 groupby를 사용하여 'Year'을 기준으로 합계를 구해 줍니다.
우리가 필요한 정보는 코로나 확진자 정보이므로 'incDec' (전일 대비 코로나 환자 수) 열의 합계만을 출력해 보겠습니다.

#groupby로 년도별 확진자 합계 확인하기(incDec: 전일대비 증감수)(2022년도는2월 23일까지)
defCnt_sum = total_df.groupby(['Year']).sum()
defCnt_sum[['incDec']]

그럼 2020년, 2021년, 2022년(1월~2월 23일까지)의 확진자 수가 집계되었습니다.
위의 데이터를 보면, 2022년도는 1,2월 두달 치의 정보만 있는데도 그 전 년도의 확진자 수를 훨씬 넘어서는 것을 확인할 수 있습니다.

날짜를 인덱스로 설정하기

datetime 을 인덱스로 지정하면 따로 조건을 지정하지 않아도 원하는 날짜 부분의 추출이 바로 가능합니다.
우선 합계 df 인 total_df가 최신 날짜 순으로 지정되어 있어 오래된 날짜 순으로 정렬한 뒤,
인덱스를 datetime 인 createDt열로 바꾸어 보겠습니다.

# 날짜를 인덱스로 설정하기
total_df = total_df.sort_values('createDt') #날짜 오래된 순으로 정렬
#인덱스를 createDt로 변경
total_df.index = total_df['createDt']
total_df

이렇게 createDt로 인덱스가 세팅 되었습니다.
또는 date_range를 사용해서도 날짜인덱스 설정이 가능한데,
주의할 점은 날짜형의 열을 index로 설정 후 reindex를 해야 한다는 점입니다.

pd.date_range(start = '시작날짜' , end= '종료날짜')
# 날짜 인덱스 설정 방법2(시간 범위): date_range
index_dates = pd.date_range(start=total_df['createDt'].min(), end=total_df['createDt'].max())
# or
index_dates = pd.date_range(start='2020-01-20', end='2022-02-23')
index_dates
# index_dates로 날짜형으로 변경하기
## reindex
# ※date range 사용 시에는 꼭 날짜형인 'createDt'열을 먼저 인덱스로 지정 후 아래와 같이 reindex 하기 ※
total_df.reindex(index_dates)
total_df

이렇게 인덱스가 날짜형으로 세팅되면 loc을 사용할 필요 없이 df['날짜']로 필요한 부분을 바로 추출할 수 있습니다.

#2020년도 12월 데이터만 추출하기
total_df['2020-12']

위의 .loc을 사용할 때보다 더욱 간편하게 원하는 기간의 추출이 가능합니다만,
위 사진 빨간 박스에 있는 경고메세지에서는 곧 이 기능이 사라진다고 하니 참고해 주시길 바랍니다.
loc을 사용하라고 권장하고 있네요.

시각화

마지막으로 위의 날짜로 인덱스를 세팅한 데이터프레임에서 전체 기간의 코로나 확진자 수(incDec)를 시각화 해보도록 하겠습니다.

# 확진자 수 시각화
#그래프 그리기
import matplotlib.pyplot as plt
ax = plt.subplots()
ax = total_df['incDec'].plot()
plt.show()

그래프도 볼 수 있듯이 2022년 들어서 확진자가 매우 가파르게 증가하는 것을 확인할 수 있습니다.

전체 코드
TimeSeriesData.ipynb
0.20MB
참고자료

1. pandas 공식문서
https://pandas.pydata.org/docs/user_guide/timeseries.html

Time series / date functionality — pandas 1.5.0 documentation

Time series / date functionality pandas contains extensive capabilities and features for working with time series data for all domains. Using the NumPy datetime64 and timedelta64 dtypes, pandas has consolidated a large number of features from other Python

pandas.pydata.org

2. [도서] Do it! 데이터 분석을 위한 판다스 입문(이지스 퍼블리싱)

마무리

이렇게 시계열 데이터 다루기 1편의 포스팅을 해 보았습니다.
생각보다 분량이 길어졌지만 시계열 데이터를 다룰 때 많은 도움이 될 것이라 생각합니다 :)

반응형
반응형

저번 포스팅에 이어서 mecab이라는 가상환경을 만들어 jupyter lab에서 연결하는 방법을 알아보도록 하겠습니다.

 

1. 가상 환경 생성하기

anaconda prompt를 열고 아래의 명령어를 입력하여 사용할 가상환경을 만들어 주세요.

이미 가상환경이 있는 분들은 이 단계를 건너 뛰어도 됩니다.

conda create -n 가상환경 이름 python=파이썬 버전
사용 예) conda create -n mecab python=3.8.0

그 후 가상환경을 사용할 폴더로 'cd 폴더'를 사용하여 이동하여 줍니다.

 

2. 가상 환경 활성화하기

다음으로 가상환경을 활성화 하여 보겠습니다.

 conda activate 가상환경 이름
사용 예)  conda activate mecab

이렇게 하면 맨 왼쪽 부분에 (base)에서 (가상환경 이름)으로 바뀌면서 활성화됩니다.

 

3. 가상 환경 커널 추가를 도와주는 패키지파일 설치하기

jupyter lab에 가상환경을 연동할 때 필요한 ipykernel 패키지를 설치해 줍니다.

conda install ipykernel

 

4. ipykernel로 jupyterlab 커널 가상환경 추가하기

이제 아래의 명령어를 입력하여 가상환경 커널을 추가해 줍니다.

(이 때, 사용하고자 하는 가상환경이 프롬프트에서 활성화되어있어야 합니다.)

python -m ipykernel install --user --name 가상환경이름 --display-name 가상환경이름
사용 예)
python -m ipykernel install --user --name mecab --display-name mecab

 

5. jupyter lab에서 가상환경 커널 연결하기

커널 추가가 완료되었으면 아래의 명령어로 가상환경을 비활성화하여 줍니다.

conda deactivate

다음으로, jupyter lab을 실행하여 줍니다.

jupyter lab

그 후 .ipynb 파일을 하나 만든 후 , 아래쪽에 Python3 (ipykernel)| Idle 을 클릭 해 줍니다.

그러면 아래와 같이 커널 선택 창이 나오는데

커널 목록에서 아까 추가한 가상환경을 클릭 한 후 select 를 눌러 적용해 주면 완료됩니다.

이렇게 하면 jupyter notebook에서 원하는 환경으로 코딩이 가능합니다 :)

반응형

+ Recent posts