오늘은 파이썬을 이용하여 배울 수 있는 통계학에 대해서 알아보겠습니다. 요즘 데이터 분석과 머신러닝이 대세인 만큼, 통계학의 중요성도 점점 더 커지고 있어요. 그래서 이번에 소개할 책은 바로 "파이썬으로 배우는 통계학 교과서"입니다. 이 책은 통계학의 기본 개념부터 시작해서, 파이썬을 활용한 데이터 분석 방법까지 폭넓게 다루고 있어요.

책 소개

"파이썬으로 배우는 통계학 교과서"는 통계학을 처음 접하는 사람부터 어느 정도 알고 있는 사람까지 모두에게 유용한 책이에요. 이 책은 통계학의 기초부터 시작해, 데이터 분석, 머신러닝에 필요한 확률과 회귀에 대한 개념까지 설명하고 있어요. 특히, 파이썬 라이브러리를 사용하여 통계 처리를 쉽게 할 수 있다는 점이 매력적이에요.

통계학의 기본 개념

통계학은 데이터를 수집하고 분석하여 의미 있는 정보를 도출하는 학문이에요. 기본적으로 기술통계, 추론통계, 회귀분석 등 다양한 분야로 나뉘어져 있어요. 이 책에서는 이러한 기본 개념을 쉽게 설명해 주기 때문에, 통계학에 대한 두려움을 덜 수 있어요.

파이썬 프로그래밍과 통계학

파이썬은 데이터 분석에 매우 유용한 프로그래밍 언어로, 다양한 라이브러리(예: NumPy, Pandas, Matplotlib 등)를 통해 통계적 분석을 쉽게 수행할 수 있어요. 이 책에서는 파이썬을 활용하여 통계학의 이론을 실제로 적용하는 방법을 배울 수 있어요.

기술통계의 중요성

기술통계는 데이터를 요약하고 정리하는 데 필요한 기초적인 통계 기법이에요. 이 책의 3장에서는 "기술통계"에 대해 다루고 있는데, 데이터 분류와 관측, 변수의 개념을 설명하고 있어요. 데이터 분석의 첫 단계로서 기술통계는 매우 중요하답니다.

확률과 확률분포

확률은 통계학의 핵심 개념 중 하나로, 사건이 발생할 가능성을 수치로 표현하는 방법이에요. 이 책에서는 확률과 확률분포에 대한 기본적인 이해를 돕기 위해 다양한 예시와 함께 설명하고 있어요. 확률분포는 데이터의 분포를 이해하는 데 필수적이죠.

모집단과 표본추출

모집단은 연구의 대상이 되는 전체 집단을 의미하고, 표본은 그 모집단에서 선택된 일부를 말해요. 이 책에서는 표본추출의 중요성과 방법에 대해 자세히 설명하고 있어요. 올바른 표본추출은 통계적 분석의 신뢰성을 높이는 데 큰 역할을 해요.

통계적 가설검정

가설검정은 통계학에서 매우 중요한 개념으로, 주어진 데이터에 기반하여 가설의 진위를 판단하는 방법이에요. 이 책에서는 가설검정의 기본 원리와 절차를 쉽게 설명하고 있어요. 이를 통해 독자들은 실제 데이터 분석에 적용할 수 있는 기초 지식을 쌓을 수 있어요.

통계모델과 정규선형모델

통계모델은 데이터를 설명하기 위해 수학적 모델을 사용하는 방법이에요. 정규선형모델은 통계학에서 가장 기본적인 모델 중 하나로, 이 책에서는 이를 통해 데이터의 관계를 분석하는 방법을 배울 수 있어요.

통계학과 머신러닝의 관계

마지막으로, 통계학과 머신러닝은 밀접한 관계가 있어요. 머신러닝의 많은 알고리즘이 통계학의 이론에 기반하고 있기 때문에, 통계학을 잘 이해하면 머신러닝을 배우는 데 큰 도움이 돼요. 이 책에서는 통계학의 기초를 통해 머신러닝의 개념을 쉽게 이해할 수 있도록 도와줘요.

이 책은 통계학을 배우고자 하는 모든 분들에게 추천할 만한 훌륭한 자료입니다. 파이썬을 활용하여 통계학을 배우는 데 큰 도움이 될 거예요. 통계학의 기초부터 시작해, 데이터 분석과 머신러닝까지 폭넓은 지식을 쌓을 수 있는 기회를 놓치지 마세요!

 

'책 서평' 카테고리의 다른 글

그로스 해킹 5장 ~6장  (0) 2024.11.24
그로스 해킹 3~4장  (0) 2024.11.18
밑바닥부터 시작하는 딥러닝 5를 읽고  (0) 2024.11.15
그로스 해킹 1장 ~ 3장  (2) 2024.11.10

문제 설명

이번 포스팅에서는 STATION 테이블에서 가장 짧은 도시 이름가장 긴 도시 이름을 찾는 SQL 문제를 다룹니다. 단, 조건은 다음과 같습니다:

  1. 가장 짧은 도시 이름과 그 길이를 구합니다.
    • 만약 이름이 같은 경우, 알파벳 순으로 가장 앞선 도시를 선택합니다.
  2. 가장 긴 도시 이름과 그 길이를 구합니다.
    • 마찬가지로, 이름이 같은 경우, 알파벳 순으로 가장 앞선 도시를 선택합니다.
  3. 최종 결과는 두 도시의 이름과 이름의 길이를 포함해야 합니다.

문제 해결 접근 방식

  1. 도시 이름 길이 계산: SQL의 LENGTH(CITY)를 사용하여 도시 이름의 길이를 계산합니다.
  2. 가장 짧은 도시 찾기:
    • 도시 이름 길이를 기준으로 오름차순(ASC) 정렬.
    • 같은 길이를 가진 도시가 여러 개라면 알파벳 순으로 정렬.
    • LIMIT 1을 사용해 가장 짧은 이름을 가진 도시 중 첫 번째 도시를 선택.
  3. 가장 긴 도시 찾기:
    • 도시 이름 길이를 기준으로 내림차순(DESC) 정렬.
    • 같은 길이를 가진 도시가 여러 개라면 알파벳 순으로 정렬.
    • LIMIT 1을 사용해 가장 긴 이름을 가진 도시 중 첫 번째 도시를 선택.
  4. 결과 병합:
    • UNION ALL을 사용해 두 개의 쿼리 결과를 하나로 병합합니다.

SQL 쿼리 코드

(SELECT CITY, LENGTH(CITY) AS NAME_LENGTH
 FROM STATION
 ORDER BY LENGTH(CITY) ASC, CITY ASC
 LIMIT 1)
UNION ALL
(SELECT CITY, LENGTH(CITY) AS NAME_LENGTH
 FROM STATION
 ORDER BY LENGTH(CITY) DESC, CITY ASC
 LIMIT 1);

 

예제 데이터

다음과 같은 STATION 테이블이 있다고 가정합니다:

CITYLENGTH(CITY)

Paris 5
Dubai 5
New York 8
Tokyo 5
Johannesburg 12

실행 결과

위 데이터를 기반으로 쿼리를 실행하면 다음과 같은 결과가 나옵니다:

CITYNAME_LENGTH

Dubai 5
Johannesburg 12
  • 가장 짧은 도시: 이름 길이가 5자인 도시 중 알파벳 순으로 가장 앞선 Dubai.
  • 가장 긴 도시: 이름 길이가 12자인 도시 Johannesburg.

추가 팁

  • LENGTH() 함수는 문자열의 길이를 계산할 때 유용합니다.
  • ORDER BY와 LIMIT은 데이터를 정렬하고 특정 조건에 맞는 결과를 빠르게 찾는 데 효과적입니다.
  • UNION ALL은 두 쿼리 결과를 합쳐주는 역할을 합니다. 중복 제거가 필요하다면 UNION을 사용하면 됩니다.

마무리

이번 문제를 통해 SQL에서 문자열 길이 계산과 정렬, 그리고 조건에 맞는 데이터를 선택하는 방법을 배웠습니다. 실무에서도 데이터의 최대값, 최소값, 특정 조건에 맞는 값을 찾는 데 유용하게 사용할 수 있습니다.

궁금한 점이나 개선할 방법이 있다면 댓글로 남겨주세요! 😊

'SQL' 카테고리의 다른 글

Weather Observation Station 17  (0) 2024.10.31
Weather Observation Station 16  (0) 2024.10.29
Weather Observation Station 15  (0) 2024.10.23
Weather Observation Station 14  (0) 2024.10.22
Weather Observation Station 13  (0) 2024.10.20

 

 

TODAY TIL

📌 문제 설명

두 정수 X, Y의 임의의 자리에서 공통으로 나타나는 숫자들을 사용해 만들 수 있는 가장 큰 정수를 두 수의 "짝꿍"이라고 합니다.
짝꿍을 구하는 규칙은 다음과 같습니다:

  1. X와 Y에 공통으로 나타나는 숫자만 사용합니다.
  2. 공통 숫자 중 가능한 최대 빈도수만큼 사용합니다.
  3. 공통 숫자가 없다면 -1을 반환합니다.
  4. 짝꿍이 0으로만 구성되어 있다면 0을 반환합니다.

예시

  • X = 3403, Y = 13203
    → 짝꿍: 330
  • X = 5525, Y = 1255
    → 짝꿍: 552
  • X = 12345, Y = 67890
    → 짝꿍: -1

💡 문제 해결 방법

이 문제를 해결하기 위한 단계별 접근법은 다음과 같습니다:

Step 1: 숫자의 빈도수 계산

  • X와 Y의 각 숫자가 몇 번 나타나는지를 계산합니다.
  • collections.Counter를 사용하면 간단하게 자릿수의 빈도를 구할 수 있습니다.

Step 2: 공통 숫자와 빈도수 찾기

  • X와 Y의 공통 숫자를 찾고, 각 숫자의 최소 빈도를 기준으로 사용할 수 있는 최대 빈도를 계산합니다.

Step 3: 결과 문자열 생성

  • 공통 숫자를 내림차순으로 정렬하여 가장 큰 숫자를 만듭니다.
  • 예외 처리:
    • 공통 숫자가 없다면 -1 반환.
    • 결과가 0으로만 구성되어 있다면 0 반환.

🖥 코드 구현

from collections import Counter

def solution(X, Y):
    # Step 1: 숫자의 빈도수를 계산
    count_X = Counter(X)
    count_Y = Counter(Y)
    
    # Step 2: 공통 숫자와 최소 빈도 계산
    common_numbers = []
    for num in count_X.keys():
        if num in count_Y:
            # 공통으로 등장하는 숫자 중 가능한 최대 갯수를 추가
            common_numbers.extend([num] * min(count_X[num], count_Y[num]))
    
    # Step 3: 결과 문자열 생성
    if not common_numbers:  # 공통 숫자가 없으면
        return "-1"
    
    # 숫자를 내림차순으로 정렬
    common_numbers.sort(reverse=True)
    result = ''.join(common_numbers)
    
    # 숫자가 모두 0으로만 구성된 경우
    if result[0] == "0":
        return "0"
    
    return result

 

🛠 동작 원리 설명

1. Counter를 활용한 숫자 빈도수 계산

count_X = Counter("3403")  # {'3': 2, '4': 1, '0': 1}
count_Y = Counter("13203") # {'1': 1, '3': 2, '2': 1, '0': 1}

Counter는 각 숫자의 빈도를 딕셔너리 형태로 반환합니다.

2. 공통 숫자와 최소 빈도 찾기

count_X와 count_Y의 키를 비교하여 공통 숫자를 찾고, 가능한 최대 빈도를 리스트에 추가합니다.

common_numbers = ['3', '3', '0']  # 최소 빈도를 기준으로 계산

 

3. 결과 생성

common_numbers를 내림차순으로 정렬하여 가장 큰 숫자를 생성합니다.

common_numbers.sort(reverse=True)  # ['3', '3', '0']
result = ''.join(common_numbers)   # "330"

 

⚙️ 테스트 케이스

# 테스트 케이스
print(solution("3403", "13203"))  # 330
print(solution("5525", "1255"))   # 552
print(solution("12345", "67890")) # -1
print(solution("100", "203045"))  # 0
print(solution("0", "0"))         # 0

 

결과

XY결과

3403 13203 330
5525 1255 552
12345 67890 -1
100 203045 0
0 0 0

💡 문제 풀이 요약

  1. 숫자의 빈도를 계산하여 X와 Y의 공통 숫자를 찾습니다.
  2. 공통 숫자를 기준으로 가능한 최대 빈도를 계산하여 숫자를 조합합니다.
  3. 숫자를 내림차순 정렬하여 가장 큰 짝꿍을 반환합니다.
  4. 특별 케이스 (공통 숫자가 없거나, 결과가 0)를 처리합니다.

⏳ 시간 복잡도

  • 빈도 계산: O(N + M) (X와 Y의 길이)
  • 공통 숫자 탐색 및 정렬: O(10 + K log K) (K는 공통 숫자의 수, 최대 10)

최종 시간 복잡도는 **O(N + M)**입니다.


✏️ 블로그 마무리

이 문제는 문자열 조작과 빈도 계산을 효율적으로 다루는 연습에 적합합니다.
collections.Counter와 같은 내장 모듈을 활용하면 복잡한 문제도 간단히 해결할 수 있습니다.

여러분도 자신만의 풀이법으로 문제를 해결하고 Python을 더욱 깊게 이해해 보세요! 🚀
궁금한 점이나 추가적인 개선 아이디어가 있다면 댓글로 공유해 주세요! 😊

TODAY TIL

문제 소개

햄버거 가게에서 일을 하는 상수는 햄버거를 포장하는 작업을 합니다. 재료들이 정해진 순서로 쌓이면 상수는 이를 포장합니다.
햄버거를 완성할 수 있는 순서는 아래와 같습니다:

  • [빵(1) – 야채(2) – 고기(3) – 빵(1)]

주어진 재료 배열에서 햄버거를 몇 개 포장할 수 있는지 구하는 프로그램을 작성해봅시다.


문제 예시

입력:

ingredient = [2, 1, 1, 2, 3, 1, 2, 3, 1]

출력:

2

설명:

  1. 첫 번째 햄버거는 [1, 2, 3, 1]로 완성됩니다.
  2. 두 번째 햄버거는 [1, 2, 3, 1]로 완성됩니다.
    결과적으로 2개의 햄버거를 포장할 수 있습니다.

문제 해결 접근법

  1. 스택(Stack) 활용:
    • 스택을 사용하여 재료를 추가하면서 햄버거 완성 여부를 확인합니다.
    • 햄버거가 완성되면 스택에서 해당 재료들을 제거합니다.
  2. 햄버거 완성 조건:
    • 스택의 마지막 4개의 재료가 [1, 2, 3, 1]인지 확인합니다.
  3. 시간 최적화:
    • 슬라이싱 대신 stack.pop()을 사용하여 불필요한 연산을 줄입니다.

최적화된 코드

아래 코드는 시간 초과를 방지하기 위해 최적화된 방식으로 작성되었습니다.

def solution(ingredient):
    stack = []  # 재료를 담을 스택
    count = 0   # 포장한 햄버거 개수

    for item in ingredient:
        stack.append(item)  # 스택에 재료 추가

        # 스택의 길이가 4 이상일 때 마지막 4개 요소를 직접 비교
        if len(stack) >= 4:
            if stack[-1] == 1 and stack[-2] == 3 and stack[-3] == 2 and stack[-4] == 1:
                # 햄버거 완성 -> 스택에서 제거
                stack.pop()  # 빵 제거
                stack.pop()  # 고기 제거
                stack.pop()  # 야채 제거
                stack.pop()  # 빵 제거
                count += 1  # 햄버거 개수 증가

    return count

 

코드 실행 과정

입력:

ingredient = [2, 1, 1, 2, 3, 1, 2, 3, 1]
print(solution(ingredient))  # 출력: 2

 

실행 과정:

  1. 스택에 [2] 추가 → 햄버거 완성 불가능.
  2. 스택에 [2, 1] 추가 → 햄버거 완성 불가능.
  3. 스택에 [2, 1, 1] 추가 → 햄버거 완성 불가능.
  4. 스택에 [2, 1, 1, 2, 3, 1] 추가 → 햄버거 완성! 스택에서 제거 → [2, 1].
  5. 나머지 재료를 처리하여 두 번째 햄버거 완성.

결과적으로 햄버거 2개 포장.


시간 및 공간 복잡도

  1. 시간 복잡도:
    • 각 재료에 대해 stack.append()와 비교, 제거 연산이 이루어지므로 O(n).
  2. 공간 복잡도:
    • 스택의 최대 크기는 ingredient와 동일하므로 O(n).

주요 개선 사항

  • 슬라이싱 제거:
    기존의 stack[-4:] 대신, stack[-1], stack[-2], stack[-3], stack[-4]로 개별 접근하여 연산 속도 최적화.
  • 불필요한 복사 연산 최소화:
    stack.pop()을 사용해 스택의 크기를 조정하며, 필요 없는 메모리 복사를 방지.

결론

이 문제는 스택 자료구조를 활용하여 재료의 순서를 관리하고, 햄버거 포장이 완료될 때마다 이를 제거하는 방식으로 효율적으로 해결할 수 있습니다. 최적화된 코드로 시간 초과 문제를 해결했으며, 스택 활용의 기본 개념을 연습하기에도 좋은 문제입니다.

 

 

 

TODAY TIL

환규와 태욱이는 문자열을 가지고 재미있는 "탕수육 게임"을 하고 있습니다. 게임의 규칙은 다음과 같습니다:

  1. 누가 먼저 시작할지 순서를 정합니다.
  2. 먼저 시작하는 사람이 단어의 첫 글자를 말합니다.
  3. 이후 두 사람은 번갈아 가며 다음 글자를 순서대로 말합니다.
  4. 단어의 마지막 글자에 도달하면, 다시 단어의 첫 글자로 돌아가서 반복합니다.
  5. 잘못된 글자를 말하면 게임에서 지게 됩니다.

예를 들어, 단어가 탕수육이라면:

  • 첫 번째 사람: "탕", "육", "수", "탕", "육", "수" ...
  • 두 번째 사람: "수", "탕", "육", "수", "탕", "육" ...

코드 소개

탕수육 게임의 규칙을 바탕으로, 두 사람이 번갈아 문자열을 나누어 가져가는 방식을 Python 코드로 구현했습니다. 이번 포스팅에서는 이 코드를 분석하며 어떻게 동작하는지 알아보겠습니다.

 

코드

def solution(case):
    answer = 0

    for v in case:
        player1 = []
        player2 = []
        for i, c in enumerate(v if (len(v) % 2) == 0 else v * 2):
            if i % 2 == 0:
                player1.append(c)
            else:
                player2.append(c)
        print("".join(player1))
        print("".join(player2))
    return answer


n = int(input())
games = [input() for _ in range(n)]
solution(games)

 

코드 분석

1. 함수 정의

def solution(case):
    answer = 0

 

 

  • 함수 solution은 문자열의 리스트 case를 입력으로 받습니다.
  • answer는 반환 값으로 초기화되지만, 현재는 출력 외에 사용되지 않습니다.

2. 게임 데이터 처리

for v in case:
    player1 = []
    player2 = []

 

 

  • 각 문자열 v를 순회하며, 두 사람의 문자 선택을 저장할 리스트 player1과 player2를 초기화합니다.

3. 문자열 순회 및 나누기

for i, c in enumerate(v if (len(v) % 2) == 0 else v * 2):
    if i % 2 == 0:
        player1.append(c)
    else:
        player2.append(c)

 

 

  • 문자열의 길이에 따라 처리 방식이 달라집니다:
    1. 짝수 길이: 문자열 v 그대로 사용.
    2. 홀수 길이: 문자열 v를 두 번 반복한 문자열 v * 2 사용.
      • 이렇게 하면 홀수 길이에서도 두 사람이 계속 번갈아 가며 문자를 가져갈 수 있습니다.
  • enumerate를 사용해 문자열의 각 문자와 해당 인덱스 i를 가져옵니다:
    • i % 2 == 0: 첫 번째 사람이 선택(player1에 추가).
    • i % 2 == 1: 두 번째 사람이 선택(player2에 추가).

4.결과 출력

print("".join(player1))
print("".join(player2))

 

 

 

  • 두 사람의 선택 결과를 각각 출력합니다.
  • player1과 player2 리스트의 문자를 합쳐 문자열로 변환한 뒤 출력합니다.

5.입력 및 함수 호출

n = int(input())
games = [input() for _ in range(n)]
solution(games)

 

 

  • 입력 데이터:
    • 첫 번째 줄: 게임의 수 n.
    • 이후 n개의 문자열이 게임의 데이터로 입력됩니다.
  • solution 함수에 입력 데이터를 전달하여 결과를 처리합니다.

동작 예시

입력

2
탕수육
ABC

 

처리 과정

  1. 첫 번째 게임: "탕수육"
    • player1: "탕육수" → 첫 번째 사람이 가져간 문자.
    • player2: "수탕육" → 두 번째 사람이 가져간 문자.
    • 출력:
       
탕육수
수탕육

 

2 .두 번째 게임: "ABC"

  • 문자열 길이가 홀수이므로 "ABCABC"로 확장.
  • player1: "ACB" → 첫 번째 사람이 가져간 문자.
  • player2: "BCA" → 두 번째 사람이 가져간 문자.
  • 출력:
     
ACB
BCA

 

최종 출력

탕육수
수탕육
ACB
BCA

 

코드의 한계와 개선 가능성

  1. 반복 확장 방식의 비효율성
    • 홀수 길이 문자열에서 v * 2로 확장하면 메모리를 낭비할 수 있습니다.
    • 이를 대신해 인덱스를 순환적으로 접근하면 더 효율적입니다.
  2. 리턴 값 사용
    • 현재 코드는 결과를 출력만 하고 반환하지 않습니다. 결과를 리스트로 반환하면 더 유연하게 활용할 수 있습니다.

개선된 코드

def solution(case):
    results = []
    for v in case:
        player1 = []
        player2 = []
        n = len(v)
        for i in range(n):
            if i % 2 == 0:
                player1.append(v[i % n])
            else:
                player2.append(v[i % n])
        results.append(("".join(player1), "".join(player2)))
    return results

# 입력 처리
n = int(input())
games = [input() for _ in range(n)]
result = solution(games)

# 결과 출력
for r in result:
    print(r[0])
    print(r[1])

 

결론

이 코드는 두 사람이 번갈아 문자열을 나누는 방식으로 게임을 진행하도록 구현되었습니다. 이를 통해 문자열의 반복적인 패턴을 쉽게 처리할 수 있습니다. 개선된 코드는 더 효율적으로 처리하며, 결과를 반환해 다양한 방식으로 활용할 수 있습니다.

탕수육 게임처럼 단순하지만 재미있는 문제를 통해 문자열 처리와 반복 구조에 대한 이해를 높여보세요! 😊

+ Recent posts