데이터 분석

[day45] 막상 가보면 아무 것도 아닌 게 너무 많다.

경 민 2025. 4. 1. 20:55
👩🏻‍💻  Point of Today I LEARNED 
📌 SQL
● 코드카타 (delete, max)

📌 Python 
● 기초 과제 복습 (replace, strip, title)
● 통계 기초 강의 1주차, 2주차 (1/3)

 

 

수준별 학습반

standard

^_^

 

잘못 찾아간 거 같은데

어떻게든 하면 되겠지.

 

막상 가보면 아무 것도 아닌 게 너무 많다 !

튜터님이 열정적으로 짜주신 커리 차근차근 잘 따라가보자.


1. SQL 

1-1. 코드카타 제한시간 두고 풀기

1) 코드카타 122번

https://leetcode.com/problems/delete-duplicate-emails/

⭐️ 중요 Point ! 
delete from 테이블 where 조건

1. from절에는 원본 테이블이 필요하다.
   서브쿼리 불가, join 가능

2. where절 서브쿼리에 ( SELECT * FROM person ) 한 번 더 감싸줘야 한다.

  → 에러 해석: 같은 테이블을 delete/update와 from 서브쿼리에서 동시에 참조할 수 없음.
해결 방법:
한 번 더 감싸주기
② join
③ CTE table

 

방법1. email로 그룹핑해서 id가 최소수인 행만 남기기

delete 
from person 
where id not in (
                select min(id)
                from
                    (
                    select *
                    from person 
                    ) a
                group by email
                )
  • 굳이 having count(1) > 1 안 해도 됨

방법2. email끼리 id 기준 오름차순 정렬해놨을 때 첫 번째 아니면 삭제

delete
from person
where 
id in
    (select id
    from
        (select
            id,
            email,
            row_number() over(partition by email order by id) rn
        from person) a
    where rn != 1)

 

방법3. left join

delete p
from person p
left join (
    select min(id) id
    from person
    group by email
    ) m
on p.id = m.id
where m.id is null
  • ⭐️⭐️⭐️ delete문에서 join의 역할
    • 테이블을 실제로 생성하는 것이 아니라 가상의 테이블일 뿐,
    • delete할 조건을 만드는 필터링 역할까지만 해주고 사라진다.
  • ⭐️⭐️ join해서 필터링해줄 경우 반드시 삭제할 테이블이 무엇인지 명시해줘야 한다. (delete p)

방법4. join (방법3 응용편)

delete p1   -- 삭제해라
from person p1, person p2
where 
    p1.email = p2.email  -- 이메일은 같은데
    and p1.id > p2.id    -- id가 크면

2) 코드카타 123번

https://leetcode.com/problems/second-highest-salary/

 

  • 처음 작성한 쿼리 (Wrong Answer)
    • 이유 : rn=2인 행만 남기고 싶은데 저렇게 하면 모든 행이 다 출력됨.
    • 해결 : where절 조건으로 rn=2 걸어주기
select max(salary) as SecondHighestSalary   -- max()의 역할 중요!
from (
    select *,
        row_number() over(order by salary desc) rn
    from employee
    ) a
where rn = 2

 

⭐️⭐️ max()의 역할

  • rn=2인 행이 없을 경우 max() 값 역시 존재하지 않음.
    • 이 때, 그냥 salary를 해주면 그냥 행 자체가 없기 때문에 아무것도 출력되지 않지만,
    • max(salary)를 해주면 max()값이 존재하지 않은 것이기 때문에 null을 출력해준다.

2. Python

2-1. 기초 과제

1) replace

def str_replace(text, old, new) :

    if not text or not old:   #원본 문자열이 없거나 text에 대체할 문자열이 없는 경우
        return text

    text_len = get_len(text)
    old_len = get_len(old)
    start=0  # 반복 시작 인덱스 설정
    new_text = ''   # 새로 넣어줄 빈 매개변수 생성

    while start < text_len:   # 중요! 인덱스가 text문자열 길이보다 작을 때까지만 반복해라.
        if text[start:start+old_len] == old:   # old문자열이랑 같으면
            new_text += new   # new로 대체
            start += old_len   # 시작 인덱스 재설정 (old 문자열 길이만큼 뒤에서부터)
        else:
            new_text += text[start]   # 원래 text대로 출력
            start += 1   # 시작 인덱스 재설정 (바로 뒤 문자열부터)
    return new_text

 

2) strip

def str_strip(text, remove_ch) :

    if not text or not remove_ch:
        return text

    start = 0   # 앞부분 시작 인덱스 
    while start < get_len(text) and text[start:start+get_len(remove_ch)] == remove_ch:
        start += get_len(remove_ch)
    
    end = get_len(text) -1   # 뒷부분 시작 인덱스
    while end >= 0 and text[end-get_len(remove_ch)+1:end+1] == remove_ch:
        end -= get_len(remove_ch)

    return text[start:end+1]

print(str_strip('----hello--', '-')) # 'hello'
print(str_strip('----hello--', '--')) # 'hello'

 

문자/문자열일 경우 모두 실행 가능한 함수로 응용해보았다.

비교할 text의 범위(?) 지정하는 게 약간 어려웠으나 차근차근..!

 

⭐️ 주의할 점 

이렇게 하면 무한루프에 빠진다.
이유 : text[start] 값이 remove_ch 와 다를 경우 조건을 만족하지 않기 때문에 start는 변하지 않고 계속 0이다.
그렇다고 else 문도 없기 때문에 start는 영원히 0일 수밖에 없음. 그 상태로 무한 루프 . . . . ♾️

 

 

3) title

def str_title(text) :
    
    if not text:
        return text
    
    first_code = ord(text[0])   # 첫번째 문자

    if 97 <= first_code <= 122:   # 첫번째 문자가 소문자이면
        return chr(first_code-32)+text[1:]   # 대문자로 바꾸고 나머지 문자 그대로 출력
    return text   # 조건에 해당하지 않으면 text 그대로 출력
ord() : 알파벳의 아스키코드 정수값을 반환
chr() : 아스키코드(정수값)에 해당하는 알파벳을 반환

🔸 예시
ord('a') = 97, ord('A') = 65 ▶▶ 대소문자간 차이 32
chr(97) = 'a', chr(65) = 'A'

 


2-2. 통계 기초 강의 1주차

1) 통계 방식

  • 기술 통계
    • 범주형, 수치형 데이터를 활용하여 백분위, 평균, 표준편차 등을 계산해서 이를 대표값으로 설정
    • 데이터에 대한 대략적인 특징 파악 
    • 대표적인 예시 ) 회사 매출 데이터 요약
  • 추론 통계
    • 표본 데이터로부터 신뢰구간, 가설검정 등을 통해 모집단의 특성을 추론 
    • 대표적인 예시) 일부 고객의 설문조사를 통해 전체 고객의 만족도 추정

2) 핵심 개념

표본오차 (Sampling Error)
  • 특정 표본 하나의 통계수치(평균, 표준편차 등)와 모집단의 진짜 값 간의 차이
  • '이 표본이 모집단과 얼마나 비슷한가'
  • 표본오차 줄이려면
    • 표본의 크기를 늘리거나
    • 무작위 추출로 표본이 특정 집단으로 쏠리지 않게 해야 한다.
표준오차 (Standard Error)

표준편차 / 표본수의 제곱근

  • 표본을 여러 번 뽑았을 때의 평균 즉, 표본평균의 변동성을 파악하는 지표
  • (=표본평균의 표준편차)
  • '표본평균들이 얼마나 흩어져있는가'
  • 표준오차가 작을수록 표본평균이 모평균에 가깝다는 의미
  • 표본 크기 커질수록 표준오차는 줄어든다.

⭐️ 표본오차/표준오차 정리

 

3) 신뢰구간, 신뢰수준

 신뢰구간

양 초록색 점선 사이 구간에 모집단의 평균이 있을 것이다.

  • 신뢰구간 범위에 모집단의 평균이 있을 것이다.
  • 계산 방식: 표본평균 ±Z * 표준오차 
    • 95% 신뢰수준의 Z 값은 1.96
    • 95% 신뢰수준의 Z 값은 2.58
  • 신뢰구간 계산 코드
import scipy.stats as stats

sample = np.random.choice(population, 100)

sample_mean = np.mean(sample)
sample_std = np.std(sample)

# 95% 신뢰구간 계산 (t 분포) / 자동으로 상한,하한 계산해줌
conf_interval = stats.t.interval(0.95, len(sample)-1, \   
					loc=sample_mean, \   #일반적으로 표본평균 사용
                                        scale= sample_std/np.sqrt(len(sample)))   #일반적으로 표본표준오차 사용

print(f'표본 평균: {sample_mean}')
print(f'95% 신뢰 구간: {conf_interval}')

 

 신뢰수준
  • 일반적으로 95%, 99% 신뢰수준을 많이 사용한다. 
    • 95% 신뢰수준이다. : 신뢰구간 범위에 모집단의 평균이 있을 확률이 95% 이다.
    • 99% 신뢰수준이다. : 신뢰구간 범위에 모집단의 평균이 있을 확률이 99% 이다.

4) 분포

 정규분포
  • 대부분의 데이터가 평균 주위에 몰려있는 분포 (종모양 대칭)
  • 편차에 따라 종 모양 달라짐
  • 정규분포 확인 곡선 코드
normal_dist = np.random.normal(170, 10, 1000)

plt.hist(normal_dist, bins=30, density=True, alpha=0.6, color='g')

xmin, xmax = plt.xlim()
x = np.linspace(xmin, xmax, 100)
p = stats.norm.pdf(x, 170, 10)
plt.plot(x, p, 'k', linewidth=2)
plt.title('normal distribution histogram')
plt.show()

 

⭐️⭐️ 표준정규분포 ⭐️⭐️
✔︎ 분포의 평균과 표준편차가 각각 0, 1인 분포 !
즉, 표준화를 거친 Z값의 분포
✔︎
표준화 하는 이유 : X값의 스케일이 다를 경우 절대치를 있는 그대로 받아들여 동등하게 분석할 수 없음, X값이 얼마나 흩어져있는지 즉 표준편차에 따라 값의 의미가 달라질 수 있음 → Z값으로 표준화해서 동일한 기준으로 비교하자.
✔︎ 표준화 공식
(확률변수 X값 - 평균) / 표준편차
평균에서 얼마나 떨어져있는지 그 거리를 구하고, 그 값을 표준편차 비율로 나타낸다.
= 제각각인 평균, 표준편차를 통일시키면서 하나의 분포로 합체(?)해서 Z값을 비교한다.

✔︎ 신뢰수준, Z-Score 이상치 탐색과 연결

 

롱테일분포 (긴꼬리분포)

  • 대부분의 데이터가 일부분에 몰려있고, 점점 꼬리만 이어지는 분포 형태
  • 아무리 데이터가 많아져도 정규분포를 이룰 수 없음
  • 일부가 전체에 큰 영향을 미치는 경우
    • 베스트셀러 20%가 전체 매출의 80% 차지 
    • 일부 부유층이 전체 소득에서 큰 비중을 차지
스튜던트 t 분포
  • 모집단이 작아서 표준편차를 알 수 없는 경우
  • 표본 크기 작을수록 꼬리가 두꺼워짐
  • 표본 크기 클수록 정규분포에 가까워짐