Algorithm

[백준/파이썬] 2108 통계학 - 수학, 구현, 정렬

마크투비 2022. 9. 25. 23:21

 2108번 통계학


 문제

수를 처리하는 것은 통계학에서 상당히 중요한 일이다. 통계학에서 N개의 수를 대표하는 기본 통계값에는 다음과 같은 것들이 있다. 단, N은 홀수라고 가정하자.

  1. 산술평균 : N개의 수들의 합을 N으로 나눈 값
  2. 중앙값 : N개의 수들을 증가하는 순서로 나열했을 경우 그 중앙에 위치하는 값
  3. 최빈값 : N개의 수들 중 가장 많이 나타나는 값
  4. 범위 : N개의 수들 중 최댓값과 최솟값의 차이

N개의 수가 주어졌을 때, 네 가지 기본 통계값을 구하는 프로그램을 작성하시오.

 입력

첫째 줄에 수의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 단, N은 홀수이다. 그 다음 N개의 줄에는 정수들이 주어진다. 입력되는 정수의 절댓값은 4,000을 넘지 않는다.

 출력

첫째 줄에는 산술평균을 출력한다. 소수점 이하 첫째 자리에서 반올림한 값을 출력한다.

둘째 줄에는 중앙값을 출력한다.

셋째 줄에는 최빈값을 출력한다. 여러 개 있을 때에는 최빈값 중 두 번째로 작은 값을 출력한다.

넷째 줄에는 범위를 출력한다.

 

💡 구현 아이디어


1. 산술 평균을 구한다. 이때 반올림을 한다.

이번 문제를 풀면서 처음으로 반올림을 구현해 봤는데 생각보다 엄청 간단하지는 않았다. 먼저 문제를 풀기 위해 필요한 파이썬 문법에 대해 정확하게 짚고 넘어가도록 하겠다. 내가 이 문제를 풀면서 떠올린 개념은 크게 int(), 나눗셈(/), 몫(//) 세 가지이다. 바로 파이썬 코드를 실행시켜서 결과를 확인하면 다음과 같다. 

 

# 1. int
print(int(12.7))
print(int(12.4))

print(int(-12.7))
print(int(-12.4))

# 12
# 12
# -12
# -12

 

int는 위와 같이 양수 음수 상관 없이 그냥 소수점 뒤에 숫자들을 아예 버려서 정수형을 만들어 준다.

 

# 2. 나눗셈
print(12 / 5)
print(-12 / 5)

# 2.4
# -2.4

 

나눗셈은 일반적인 숫자 사칙연산에서와 같이 - 부호 그대로 연산이 수행되고, 이때 소수점 아래 1자리까지 고려한다.

 

# 2. 몫
print(12 // 5)
print(-12 // 5)

# 2
# -3

 

주의할 점은 음수몫 연산나눗셈 연산이다. 다른 연산들은 양수와 음수의 결과가 동일한데 몫을 구하는 연산에서만 결과가 다르다. 나머지를 항상 양수로 만든다고 생각하면 헷갈리지 않을 수 있다. -12의 몫을 구하는 연산을 해보자.

-12 = 5 * (-3) + 2 이렇게 연산이 수행되어 몫이 -3, 나머지가 2로 나온다.

 

이제 다시 반올림 연산을 구현해보도록 하겠다. 소숫점 뒤 숫자를 기준으로 0.5보다 크거나 같으면 올림하고, 작으면 내림을 하면 된다. 소숫점 아래 숫자를 구하기 위해서 절댓값을 구해주는 내장함수 abs()를 사용했다.

 

div = sum(li) / n
q = sum(li) // n
r = abs(div - q)
if r >= 0.5:
    mean = q + 1
else:
    mean = q

 

2. 중앙값을 구한다.

이때 리스트를 sort() 함수를 사용하여 오름차순 정렬하고, 중앙값을 가리키는 인덱스를 구했다.

 

3. 최빈값을 구한다. 

최빈값을 구할 때는 Counter 라이브러리를 사용했다. 파이썬에서 빈도수를 구할 때 아주 유용한 라이브러리이다. 리스트 li에 대해서 최빈값을 구하려고 할 때 다음과 같이 라이브러리를 사용하면 된다.

 

from collections import Counter
cnt = Counter(li)
cnt_li = cnt.most_common()

# li = [-1, -2, -3, -1, -2]
# cnt_li = [(-2, 2), (-1, 2), (-3, 1)]

 

위와 같이 most_commont()을 사용하면 튜플 형태로 (리스트 요소 값, 등장한 횟수)를 반환한다. 이름이 most_common()인 것에서 알 수 있듯이 가장 많이 등장한 횟수 순으로 정렬된다. 

 

4. 범위를 구한다.

min()과 max()를 이용해서 리스트의 최솟값과 최댓값을 구했다.

 

위 문제를 구현한 전체 소스코드는 다음과 같다. 

 

💻 소스 코드


import sys
input = sys.stdin.readline

# 입력
n = int(input())
li = [int(input()) for _ in range(n)]

# 1) 산술 평균
div = sum(li) / n
q = sum(li) // n
r = abs(div - q)
if r >= 0.5:
    mean = q + 1
else:
    mean = q
print(mean)

# 2) 중앙값
mid = n // 2
li.sort()
print(li[mid])

# 3) 최빈값 - 라이브러리 사용하기
from collections import Counter
cnt = Counter(li)
cnt_li = cnt.most_common() # 등장한 횟수 내림차순으로 정렬
if len(cnt_li) >= 2:
    if cnt_li[0][1] == cnt_li[1][1]:
        print(cnt_li[1][0])
    else:
        print(cnt_li[0][0])
else:
    print(cnt_li[0][0])

# 4) 범위
ran = max(li) - min(li)
print(ran)