728x90

데이터 분석 스터디를 하면서 기본적인 사용방식, 시각화 방식을 익혔다.

이를 적용하는 연습을 해보기로 하였다.

이번에 연습해볼 데이터는 2016년부터 2021년까지 인구 변화를 파악하는 것이다.

 

import pandas as pd
import matplotlib.pyplot as plt

 

일단 기본적으로 import 해야 하는 것들은 해주었다.

중간에 필요한 것들은 아래에서 진행할 예정이다.

 

전국 인구의 변화

먼저 전국 인구 변화가 궁금했다.

 

file=pd.read_excel('201612_202112_연령별인구현황_연간.xlsx',skiprows=3,index_col='행정기관',usecols='B,C,AP,CC,DP,FC,GP')
file.iloc[0]=file.iloc[0].str.replace(',','').astype(int)
file

 

그래서 파일을 읽어들인 다음에 행정기관 row를 header로 만들어주었다.

그리고 년도별 인구 현황을 작업하였는데 연도별 추출이 제대로 되지 않아 해당 column을 직접 설정해서 진행하였다.

 

결과는 정상적으로 출력되었다.

그리고 전국 데이터에 대한 꺾은선 그래프 처리를 위해 전국 데이터에 있는 ',' 표시 역시 제거해주는 작업을 해주었다.

 

file.columns=[2016,2017,2018,2019,2020,2021]
file

 

그러나 같은 이름의 탓인지 연도 구분이 되지 않았다.

그래서 column이름을 직접 바꾸기로 결정.

16년도부터 21년도이기에 적은 개수의 column으로 직접 리스트에 넣어서 만들어주었다.

 

그럼 헤더의 총인구수.1 이런 표시가 연도로 변경된 것을 확인할 수 있다.

 

all=file.iloc[0]
all

 

다음 과정에서 바로 변화 그래프를 그리고 싶었지만, 처리가 안되는 관계로 첫번째 row를 뽑아서 all이라는 변수에 넣어주었다.

 

그래서 정상적으로 값이 들어온 것을 확인하고 이제 그릴 준비를 해보자

 

import matplotlib
matplotlib.rcParams['font.family']='Malgun Gothic'#Windows
#matplotlib.rcParams['font.family']='HYGungSo-Bold'#Windows
matplotlib.rcParams['font.size']=15 #글자 크기
matplotlib.rcParams['axes.unicode_minus']=False # 한글 폰트 사용시 마이너스 글자가 깨지는 현상을 해결

 

변화 그래프를 그릴 때 한글로 하면 글자가 깨지는 현상이 발생할 수 있는데 이를 방지하는 작업을 해주었다.

맑은 고딕으로 포늩를 설정하고 크기, 그리고 한글폰트 사용시 깨지는 현상을 False로 처리해주었다.

 

plt.suptitle('전국 인구 변화')
plt.plot(all,color='red',marker='o')

 

가장 보기 쉬운 형태로 보자

그래프 이름은 전국 인구 변화이고

그래프에 넣은 데이터는 all 데이터, 색은 빨간색, 원형마커로 좀 더 명확히 표시해주었다.

 

 

전국 인구 변화를 보니 19년도까지 인구가 증가하다가 20년 조금 감소하였다.

2021년에는 2016년보다 더 적은 인구로 굉장히 감소한 것을 확인할 수 있었다.

 

 

남성 인구의 변화

 

그럼 어디서 큰 변화가 일어났을까?

남녀를 동시에 그리면 좋겠지만 일단 먼저 남성 인구를 알아보기로 하였다.

 

file_m=pd.read_excel('201612_202112_연령별인구현황_연간.xlsx',skiprows=3,index_col='행정기관',usecols='B,P,BC,CP,EC,FP,HC')
file_m.iloc[0]=file_m.iloc[0].str.replace(',','').astype(int)
file_m

 

전국인구와 마찬가지로 엑셀에서 해당 셀만 불러오기로 하였다.

인구 수에서 나오는 ','표시도 제거해서 file_m이라는 변수에 넣어주었다.

 

전국 데이터를 불러왔다.

 

file_m.columns=[2016,2017,2018,2019,2020,2021]
file_m

 

마찬가지로 연도별로 표시되도록 column명을 변경해준 뒤

 

 

all_m=file_m.iloc[0]
all_m

 

전국 row에 있는 데이터만 넣어준 후 

 

plt.title('남성 인구의 변화')
plt.plot(all_m,color='blue',marker='o')

 

앞에것과 같이 title만 변경해준 뒤 파란색 선으로 그려주게 되면

 

남성 인구도 전국 인구와 비슷한 형태의 모양을 띄는 것을 확인할 수 있다.

 

 

여성 인구의 변화
file_w=pd.read_excel('201612_202112_연령별인구현황_연간.xlsx',skiprows=3,index_col='행정기관',usecols='B,AC,BP,DC,EP,GC,HP')
file_w.iloc[0]=file_w.iloc[0].str.replace(',','').astype(int)
file_w

 

여성 인구 역시 그려나가는 방식은 남성 인구와 같다.

 

이렇게 전국 데이터를 확인할 수 있고 여기서 전국 데이터만 살펴보자

 

file_w.columns=[2016,2017,2018,2019,2020,2021]
file_w

 

일단 여기 헤더도 연도로 다 바꿔주고

all_w=file_w.iloc[0]
all_w

 

전국 데이터만 뽑아준다.

 

plt.title('여성 인구의 변화')
plt.plot(all_w,color='pink',marker='o')

 

여성인구의 변화라는 title로 분홍색으로 그래프를 그려주게 되면

 

 

여성은 20년도까지 증가하다가 21년도에 줄어든 것을 확인할 수 있다.

 

이번 포스팅에서는 전국 남여 인구, 남성인구, 여성인구를 살펴보았다.

 

다음 포스팅에서는 나이대별로 비교를 해보려고 한다.

이렇게 직접 그려보면 인구 동향도 확실히 알 수 있을 것이고 이 과정에서 여러가지 처리 및 시각화 방식도 익힐 수 있을 것이라고 본다.

 

728x90
728x90

https://www.acmicpc.net/problem/1021

 

1021번: 회전하는 큐

첫째 줄에 큐의 크기 N과 뽑아내려고 하는 수의 개수 M이 주어진다. N은 50보다 작거나 같은 자연수이고, M은 N보다 작거나 같은 자연수이다. 둘째 줄에는 지민이가 뽑아내려고 하는 수의 위치가

www.acmicpc.net

문제

지민이는 N개의 원소를 포함하고 있는 양방향 순환 큐를 가지고 있다. 지민이는 이 큐에서 몇 개의 원소를 뽑아내려고 한다.

지민이는 이 큐에서 다음과 같은 3가지 연산을 수행할 수 있다.

  1. 첫 번째 원소를 뽑아낸다. 이 연산을 수행하면, 원래 큐의 원소가 a1, ..., ak이었던 것이 a2, ..., ak와 같이 된다.
  2. 왼쪽으로 한 칸 이동시킨다. 이 연산을 수행하면, a1, ..., ak가 a2, ..., ak, a1이 된다.
  3. 오른쪽으로 한 칸 이동시킨다. 이 연산을 수행하면, a1, ..., ak가 ak, a1, ..., ak-1이 된다.

큐에 처음에 포함되어 있던 수 N이 주어진다. 그리고 지민이가 뽑아내려고 하는 원소의 위치가 주어진다. (이 위치는 가장 처음 큐에서의 위치이다.) 이때, 그 원소를 주어진 순서대로 뽑아내는데 드는 2번, 3번 연산의 최솟값을 출력하는 프로그램을 작성하시오.

 

첫째 줄에 큐의 크기 N과 뽑아내려고 하는 수의 개수 M이 주어진다. N은 50보다 작거나 같은 자연수이고, M은 N보다 작거나 같은 자연수이다. 둘째 줄에는 지민이가 뽑아내려고 하는 수의 위치가 순서대로 주어진다. 위치는 1보다 크거나 같고, N보다 작거나 같은 자연수이다.

 

출력

첫째 줄에 문제의 정답을 출력한다.

 

입력 예시
10 3
1 2 3

 

출력 예시
0

 

코드 및 설명
from collections import deque
import sys
#where=list()
n,m=map(int,sys.stdin.readline().split())
line=deque([i+1 for i in range(n)])
where=list(map(int,sys.stdin.readline().split()))
answer=0
for i in where:
    

    while True:
        if line[0]==i:
            line.popleft()
            break
        else:
            if line.index(i)<=len(line)//2:
                line.rotate(-1)
                answer+=1
            else:
                line.rotate(1)
                answer+=1
        
print(answer)

이 문제는 문제를 이해하는 것이 중요하다고 생각이 든다. 나 역시도 이 구조가 어떻게 하는 방식인지는 이해했지만 방식을 어떻게 활용해야 하는지 감을 못잡았기 때문이다. 일단 문제를 이해해보도록 하자.

 

3가지 연산을 할 수 있다고 한다.

 

첫번째 연산은 단순히 앞에 있는 숫자를 뽑아낸다고 생각하면 된다. 즉 맨 앞에 있는 숫자가 원하는 위치의 숫자일 때를 의미한다. 그러면 다른 숫자의 이동 없이 뽑아내면 된다. 그렇게 되면 이 문제에서 최종적으로 출력하는 이동 정도 값에는 영향이 없다.

 

두번째 연산과 세번째 연산에 대한 이해를 해보도록 하자. 먼저 방식을 이해해보자면 배열에서 각각을 왼쪽으로 이동하게 되면 맨 앞에 있는 숫자는 맨 뒤로 이동한다. 세번째 연산은 그 반대이므로 각각 오른쪽으로 이동한 뒤 가장 뒤에 있는 값은 맨 앞으로 오게 한다. 여기서 이동할 때마다 이동한 정도를 더해주어야 한다. 

 

그럼 코드에 대해서 보도록 하자.

이 문제는 앞뒤로 뽑고 해주어야 하므로 덱 문제이다. 그래서 deque로 리스트를 만들어 주었고 입력 받는 것 역시 리스트 형태로 구분해서 받도록 해주었다. 이후 for문으로 입력받은 값이 반복되는 동안 안의 코드를 실행하도록 하였는데 맨 앞의 값과 해당 값이 같으면 바로 뽑고 break를 걸었고 아니라면 이제 길이를 재서 중간보다 작다면 2번 연산, 아니라면 3번 연산을 하도록 해주었다. 

 

여기서는 rotate라는 명령어를 활용하였다. 단계별 풀어보기의 이 문제 앞에 있는 덱 문제에서는 popleft라는 것을 통해서 숫자를 뽑아내는 방식을 택했다. 이 문제도 가능하다. 뽑아서 가장 뒤로 추가해주면 되니까. 그렇게 되면 line.append(line.popleft()) 이렇게 해주면 될것이다. 반대의 경우에도 line.appendleft(line.pop())를 이용해 해주게 되면 똑같이 실행된다. 

 

이 방식은 뽑고 다시 추가를 해줘야 한다는 점에서 코드 길이는 변화는 없지만 복잡해보인다. 뽑고 알아서 추가해주는 것을 대신 해주는 것이 rotate라는 명령어이다. 이제 1을 넣게 되면 각각 오른쪽으로 이동해 맨 뒤에 값이 맨 앞으로 오게 된다. -1을 넣어주면 반대로 왼쪽으로 이동해 맨 앞의 값이 맨 뒤에 값으로 이동할 것이다. 좀 더 편하게 해주는 것이라고 볼 수 있다.

 

두가지 방식을 해보면서 덱의 개념을 이해해보는게 좋을 것 같다는 생각이 든다.

728x90

'Python > Baekjoon' 카테고리의 다른 글

[Python] 백준 1920 수찾기  (0) 2022.07.07
[Python] 백준 2630 색종이 만들기  (0) 2022.07.04
[Python] 백준 10866 덱  (0) 2022.05.14
[Python] 백준 9375 패션왕 신혜빈  (0) 2022.05.10
[Python] 백준 1934 최소공배수  (0) 2022.05.07
728x90

코딩을 위해 코드를 짜다보면 시간복잡도를 고려해야 한다는 것을 한번씩 듣게 된다.

시간 복잡도란 무엇일까?

 

입력값의 변화에 따라 연산을 실행할 때, 연산 횟수에 비해 시간이 얼마만큼 걸리는가에 대한 것이다.

 

이것은 효율적인 알고리즘을 구현하기 위해서 사용하게 되는데 주로 빅-오 표기법을 사용한다.

 

이 Big-O 표기법에는 크게 5가지가 있다.

1. O(1)

2. O(n)

3. O(log n)

4. O(n2)

5. O(2n)

 

1. O(1): 일정한 복잡도, 입력값이 증가하더라도 시간이 증가하지 않음.

printf("time");

말 그대로 값을 넣으면 즉시 나온다는 것이다.

계산하기 위해 반복을 돌릴 필요가 없다는 얘기이다. 즉시 나오기 때문에 1이 시간복잡도를 가진다.

 

 

2. O(n): 선형복잡도, 입력값이 증가함에 따라 시간 또한 같은 비율로 증가하는 것을 의미함.

for i in range(n):
	printf("hello")

입력값(n)이 늘어나는 만큼 동일한 비율로 증가하는 것을 의미한다. 입력값이 많으면 많을수록 시간이 더 오래걸릴것이다. 늘어난다고 무조건 O(n)인 것은 아니다. 입력값이 증가할 수록 같은 비율로 증가해야 한다.

1이 늘어날 때 걸리는 시간이 5초씩 더 늘어난다면 O(5n)이 되므로 선형복잡도라고 할 수 있다.

 

3. O(log n): 로그 복잡도로 빅오 표기법 중 O(1)다음으로 빠른 시간이 소요

어떤 숫자를 찾는다고 하자
추리한 숫자를 말한다. 그럼 이 숫자보다 큰지 작은지 알려준다.
그리고 그 범위 안에서 다시 반복한다. 큰지 작은지 알려주면서 범위를 좁힌다.
경우의 수를 절반으로 줄여나간다.

이것을 이해하기 위해서는 탐색 기법을 떠올려보아야 한다.

리스트 혹은 배열에서 찾을 때 up, down으로 숫자를 맞춰나가는 과정을 생각하면 된다.

전체를 탐색해야 하는 것보다 절반으로 줄어들기 때문에 빠르게 탐색을 할 수 있다. 

이 예시로는 이진 탐색 트리를 생각하면된다.

트리에서 두개 이상으로 계속해서 갈라지는 것을 반복하다보면 원하는 값에 도달할 수 있다.

 

4. O(n2): 2차 복잡도, 입력값이 증가함에 따라 시간이 n의 제곱수 만큼 걸리는 것을 의미

for i in range(n):
	for j in rnage(n):
    	print("hello")

입력을 했을때 제곱값만큼 걸리게 되면 이 복잡도에 해당한다고 할 수 있다.

예를 들면 이중 for문이라고 할 수 있을 것이다.

생각을 해보게되면 for문이 0부터 4까지 5번씩 반복하는게 이중,삼중으로 하게 되면 제곱, 세제곱으로 걸리게 된다. 이렇게 증가하게 되는 것을 2차 복잡도라고 한다. 이 예시에서느 반복횟수가 같지만 만약에 다르다면 시간복잡도는 O(nm)이런 형태로도 될 것이다.

 

5. O(2n): 기하급수적 복잡도. 가장 느린 시간 복잡도

def fibo(n):
	if n<=1:
    	return 1
    fibo(n-1)+fibo(n-2)

n=int(input())
fibo(n)

이 복잡도 식에서 볼 수 있는 것처럼 기하급수적으로 굉장히 늘어난다는 것이다. 대표적인 예시로는 재귀가 있다. 재귀는 반복해서 호출하기 때문에 기존보다 몇배씩 증가할 수 밖에 없고 그래서 시간 역시 오래 걸리는 구조가 되게 된다.

 

 

이 5가지가 시간 복잡도의 대표적인 사례이다. 이외에도 여러가지 복잡도가 존재한다.

알고리즘, 자료구조를 학습하게 되면 이 복잡도가 보이게 되고 고려하게 된다. 

지금 완전히 이해하기 보다는 알고리즘 개념과 관련 코드를 보다보면 자연스럽게 이해가 될 것이라고 예상한다.

 

-참고자료

https://hanamon.kr/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-time-complexity-%EC%8B%9C%EA%B0%84-%EB%B3%B5%EC%9E%A1%EB%8F%84/ 

 

[알고리즘] Time Complexity (시간 복잡도) - 하나몬

⚡️ Time Complexity (시간 복잡도) Time Complexity (시간 복잡도)를 고려한 효율적인 알고리즘 구현 방법에 대한 고민과 Big-O 표기법을 이용해 시간 복잡도를 나타내는 방법에 대해 알아봅시다. ❗️효

hanamon.kr

 

728x90

+ Recent posts