4주차 필기록 통합본

김다피·2026년 1월 30일

SKN-25 필기본

목록 보기
4/14
post-thumbnail

Day1

머신러닝은 이제 보조의 영역이지만 종종 작은 모델을 만들어야할 때가 올 수 있으니, 그 때를 위한 라이트한 준비.

🟢 데이터분석 관련 통계

대학교 수업에서의 머신러닝 = 데이터마이닝 = 패턴인식

평균의 함정 → 중앙값은 높지 않음.

🔵기술통계

  • 자료 요약 및 조직화, 단순화하는데 목적이 있음. 평균, 중앙값, 최빈값, 편차 등등(describe() 찍으면 나옴)
  • 명목 척도를 대상으로 하는 빈도 분석과 비율 척도 분석이 대표적임
  • 모집단의 특성을 유추하는데 사용할 수 있음

🔵 추론통계

  • 표본에서 얻은 통계치로 통계를 냄
  • 샘플링을 어떻게 할지도 중요함
  • 표본 통계치 바탕으로 모수를 확률적으로 추정하는 통계 기법
  • 품질 쪽에서 많이 쓰임 ex) 6 sigma , 여기서 시그마는 표준 편차.
  • 밝혀지지 않은 데이터를 추론해야 함.
  • T 분포. ⇒ 샘플이 많아지면 정규분포와 비슷해짐..
    • 윌리엄 실리 고셋이 만듦.

표본에서 얻은 기술 통계로 모집단의 특성과 정보를 추리하는 것이 추론통계

통계학은 설명이 가능해야한다.

🔵 중앙값

  1. 정렬을 한다.
  2. 순서 중 중앙에 오는 값을 택한다.

🔵 통계 관련 파이썬 라이브러리

statsmodels → 진짜 통계

scipy.stats →빠른 통계

numpy → 선형대수

type(np.array([1,2,3]))

numpy.ndarray

np.array([1,2,3])*5

array([ 5, 10, 15]) → 브로드캐스팅

numpy는 c로 이루어져있어서 C와는 속도 비슷할 수 있음.

파이썬이 무거워서 느린데도 사용하는 이유 → numpy

np.array([[1,2,3],[4,5,6]]) # matrix
np.array([[[1,2,3],[4,5,6]]]) #tensor

TPU

  • tensor processing unit. ai 연산 시 쓰는 프로세서
np.arange(16).ndim #1

이상치, 최빈값, 중앙값, 평균.

🟢데이터 종류

Categorical data ⇒ 질적 데이터

import pandas as pd
pd.DataFrame({'a':[1,2,3,4]}).describe()
a
count4.000000
mean2.500000
std1.290994
min1.000000
25%1.750000
50%2.500000
75%3.250000
max4.000000

🔵양적 데이터

  • 연속형 데이터 → 주로 적분(더하다)
  • 이산형 데이터 → 시그마 (더하다)

🔵 질적 데이터(Categorical Data)

  • 명목형 데이터 → 순서나 우열이 없음
  • 순서형 데이터 → 순서는 있지만 차이가 균일하지 않음.
  • 컴퓨터가 질적 데이터를 이해하지 못하기 때문에 라벨을 달아줌
    • encoding (One-hot, Label encoding)
  • Label encoding
    • 초등 0 중등 1 고등 2 대학 3 식으로 달림.
    • 숫자가 클 수록 진짜 의미가 있는가? 아닐 수 있음. 그저 치환이라면 정보 전달에 오류 가능
  • one-hot encoding
    • 각 카테고리별로 컬럼을 생성해준다. 해당하는 데이터에 1을 넣고, 나머지는 0.

🔵 이진 데이터

  • 질적 데이터의 특수한 형태, 단 두 개의 범주로 나뉨
    • 합격/불합격, 예/아니오.

🔵 시계열 데이터

  • Time-series data, 시간 순서에 따라 기록된 데이터
  • ex) 주식 가격, 일일 기온, 월별 매출

🔵 공간 데이터

  • Spatial Data
  • 지리적 위치 정보가 포함된 데이터
  • GPS 좌표, 지도상의 지역별 인구 분포

🟢분석 방법

🔵질적 데이터 분석

  • 막대 그래프

🔵양적 데이터 분석

  • 히스토그램, box plot, 산점도
  • t검정, anova, 회귀분석

🔵편차

  • 평균값으로부터 얼마나 떨어져 있는지.
  • 편차를 다 더하면 0이 나온다 → 평균을 구하면 0
  • 편차를 다 제곱해서 더해서 개루로 나누면 분산. 그걸 루트하면 표준편차.(시그마)

ex) 평균이 60, 당신은 75점을 받았다.

이 때 표준편차가 12점일 때보다 8점일 때보다 언제가 더 좋은가? ⇒ 8점.

왜? 주로 그 편차 안에 70퍼 정도가 들어가 있으므로, 상위 20,30퍼 정도됨을 의미할 수 있다.

표준편차 +-2배보다 멀리 떨어진 데이터는 좌우 양쪽 합쳐서 5%밖에 없다 생각하면 대략 맞다.

import pandas as pd
pd.DataFrame({'a':[1,2,3,4],'b':['남','남','여','여']}).describe(include='all')
ab
count4.0000004
uniqueNaN2
topNaN
freqNaN2
mean2.500000NaN
std1.290994NaN
min1.000000NaN
25%1.750000NaN
50%2.500000NaN
75%3.250000NaN
max4.000000NaN

mean 평균

std : 표준편차

a : 양적 데이터

b : 질적 데이터

매번 컴퓨터를 켜서 실행할 수 없으므로, 스케쥴러를 사용함

그 스케쥴러가 airflow. 신입사원 우대.

네카라쿠배 안쓸 수 없음.

MLops 관리.

최종 프로젝트에는 airflow 사용하면 좋다.

kbo.shape ## 형상 보는거. (913,14)

913→ 관측 데이터, row

14 → 설명변수(통계), feature, colunms.

kbo.head(3)
kbo.info()
kbo.isnull().sum()
kbo.HEIGHT.dtype

dtype('int64') #8바이트. 8*8

비트 8개 모이면 바이트

type(np.nan) #float, 결측치가 float 형태임.
kbo.HEIGHT.mean() #np.float64(182.91347207009858)
kbo.HEIGHT.std() #4.949101049590222
print(kbo.HEIGHT.mean()-kbo.HEIGHT.std())
print(kbo.HEIGHT.mean()+kbo.HEIGHT.std())

177.96437102050837
187.8625731196888

  • 이 안에 kbo 선수들 키 70프로가 들어가 있음.

-1.818e-12는 왼쪽 방향으로 소수점 12번 이동. 즉 0과 비슷한 값이라 볼 수 있음.

help(kbo.HEIGHT.std)

기본값 =1

ddof를 0으로 넣는다면. → 자유도

Delta Degrees of Freedom.

🔵자유도

  • 우리가 다루는 데이터 → 샘플
  • 샘플의 분산값이 상대적으로 작게 나타나는 현상을 발견함.
  • 분모의 값을 하나 정도 빼서 값을 맞춰주기로 결정한다.
  • 5개 중 하나가 20이어어야 할 때, 4개는 아무거나 넣어도 되지만, 나머지 1개는 무조건 20을 선택해야한다.
  • 판다스는 ddo가 1으로 되어있다. (모집단을 사용한다고 가정하기 때문에.)
  • 넘파이는 ddof가 0으로 되어있다.

🔵불편분산

  • 표본분산은 모집단의 분산에 비해 과소평가되는 경향이 있음.
  • 이렇게 분모를 N-1로 사용하는 것이 불편분산.

1,2,3,4분위값.

평균 → 뮤(𝜇, Mu)

표준편차 - 시그마(𝜎, Sigma)

  • 95% 안에 들어갈 값이 들어가는 부분이 X이다.

🔵데이터는 어느 분포에서 왔는지에 따라 다루는 방법이 달라진다.

  • 모수적 통계

⇒ 비모수적인건? 출신을 모르겠는 것이다.

정규분포

  • 데칼코마디처럼 양쪽이 동일하게 생겼다.

딥러닝에서 보는 분포 → 유니폼 분포, 베타 분포, 디리클레 분포(gpt 전에 자연어처리에서 사용했었음)

LDA??? 문서 정리 방법론

kbo.TEAM.value_counts()

kbo.sort_values(by='SALARY',ascending=False)
  • 기본 값 : 오름차순
kbo.sort_values(by=['SALARY','HEIGHT'],ascending=[False,False])
  • 여러 개도 가능
kbo[kbo.TEAM =="KT 위즈"]
kbo.query("TEAM == 'KT 위즈' ")
  • sql에서의 where문과 비슷.
kbo.drop(0) #그냥은 인덱스 기준
kbo.drop(["ID"],axis=1) #row와 컬럼 둘 다 지울 수 있다.
kbo.drop(["ID"],axis=1,inplace=True) #row와 컬럼 둘 다 지울 수 있다.
kbo.groupby(['TEAM','POSITION'])[['SALARY']].mean().index

MultiIndex([('KIA 타이거즈', '내야수(우투우타)'),
('KIA 타이거즈', '내야수(우투좌타)'),
('KIA 타이거즈', '내야수(좌투좌타)'),
('KIA 타이거즈', '외야수(우투우타)'),
('KIA 타이거즈', '외야수(우투좌타)'),
('KIA 타이거즈', '외야수(좌투좌타)'),
('KIA 타이거즈', '투수(우언우타)'),
('KIA 타이거즈', '투수(우투양타)'),
('KIA 타이거즈', '투수(우투우타)'),

kbo.groupby(['TEAM','POSITION'],as_index=False)[['SALARY']].mean().index
kbo.POSITION.unique()
  • sql의 distinct 개념
#파생변수
kbo['POSITION_2'] = kbo['POSITION'].apply(lambda x : x.split("(")[0])
kbo['POSITION_2'].unique()

array(['내야수', '투수', '포수', '외야수'], dtype=object)

kbo['POSITION_2'].value_counts()

POSITION_2
투수 476
내야수 205
외야수 156
포수 76

kbo.groupby(['TEAM','POSITION_2'],as_index=False)[['SALARY']].mean()

kbo.sort_values(by=['HEIGHT'],ascending=False,inplace=True)
kbo.groupby('TEAM').first()

키로 정렬 후 first 뽑으면 각 팀 1등 출력 가능.

kbo.groupby('TEAM').nth(1)

  • first 제외하고는 nth(숫자)로 순위 보기 가능
kbo.sort_values(by=['WEIGHT']).groupby('TEAM').first()
  • functional programming : 배달사고가 안남

  • 보통 통계 교수님들은 빈도주의 통계.

  • 현재는 베이지안 통계가 각광받을 수 있다. 컴퓨터가 연산하기 때문에!

  • 과거에는 연산량이 많으므로 무시받아왔다.

  • 현재는 Gpt 등 언어모델이 베이지안 통계 기반이다.

Day2

데이터 전처리 → SQL, Pandas

R ⇒ dplyr

🟢데이터 분석 순서

  1. 주제(과제) 선정
    1. 가설 설정(도메인 필요)
  2. 데이터 추출
  3. 전처리
  4. 모델 학습
  5. 성능 평가
  6. 배포

🔵메소드 소개

df2=df

df2.loc[1,'c2'] =99

df #바라보는 곳이 같아서 df가 수정됨.
print(id(df))
print(id(df2))

2104847279376
2104847279376

  • 둘이 같은 곳을 바라보고 있음.
df3=df[['c0','c1']]
df3
df3['c0']=df3['c0']*10
  • df3은 df로 뽑아낸 뷰를 저장해서 쓰는 것이므로, copy()를 하는 것이 좋음.

🔵사용 데이터 크롤링하기

차트에서도 얻을 수 있다.

import pandas as pd
import requests

url=\
    "https://m.stock.naver.com/front-api/external/chart/domestic/info?symbol=005930&requestType=1&startTime=20250428&endTime=20260121&timeframe=day"

r=requests.get(url)
eval(r.text.strip())

image.png

  • 문자열로 된 코드를 eval이 알아서 리스트 형태로 바꾼다.
  • 보안 취약하나 python에는 아직 남아있다.
df2 = pd.DataFrame(eval(r.text.strip())[1:],
                   columns=eval(r.text.strip())[0])
# eval(r.text.strip())
df2['MA20']=df2 ['종가'].rolling(20).mean()
  • 이동 평균 내기.(moving average)
df2.dropna()
  • 결측치 제거
# 열 이름 중, '나이'를 '연령'으로, '성별'을 '남녀'로, '학교'를 '소속'으로 바꾸기
df = df.rename(columns={'나이':'연령', '성별':'남녀', '학교':'소속'})
  • 열 이름 수정
# df의 행 인덱스 중에서, '준서'를 '학생1'로, '예은'을 '학생2'로 바꾸기
df = df.rename(index={'준서':'학생1', '예은':'학생2' })

# df 출력(변경 후)
print(df)
  • 인덱스도 수정할 때가 있다.
# 데이터프레임 df를 복제하여 변수 df2에 저장. df2의 1개 행(row)을 삭제
df2 = df.copy()
df2 = df2.drop('우현')
print(df2)
  • drop의 기본값은 row, 컬럼 삭제 원하면 axis=0,1 조절
# 데이터프레임 df를 복제하여 변수 df4에 저장. df4의 2개 행(row)을 삭제
df4 = df.copy()
df4 = df4.drop(['우현', '인아'], axis='index')
print(df4)
  • axis 설정 이렇게도 가능하지만 굳이.
df.transpose()
  • 행렬 전환
  • 내적.
np.dot(np.arange(6).reshape(2,3),np.arange(6).reshape(2,3).T)
  • 둘이 곱함(dot product.)
import random
import numpy as np
import pandas as pd

np.random.randint(9)
data = [np.random.randint(100) for x in range(100000)]
tmp = pd.DataFrame({'a': data})

import time
start = time.time()
for idx, x in tmp.iterrows():
    tmp.iloc[idx] = x.values[0] * 10
import time
start = time.time()
tmp['a'] = tmp['a'] * 10
print(time.time()-start)

🔵카테고리 데이터 수치화

  • catboost 제외
pd.get_dummies(titanic['sex'])
  • 원핫인코딩
pd.get_dummies(titanic['sex'],drop_first=True)
  • 첫 번째는 그냥 제거해도 될 때가 있다.
df.query(조건문)
  • 실행하고 싶은 요소 안에 문장으로 삽입

Day3

df.columns = ['mpg','cylinders','displacement','horsepower','weight',
              'acceleration','model year','origin','name']
  • 컬럼 이름 변경 : 개수가 딱 맞아야함.
df.shape
df.shape[0]

→ 데이터 건 수만 추출, [1]도 마찬가지

→ len(배열)처럼 개수처럼 사용하기 좋음.

import numpy as np
df.loc[2,'cylinders']=np.nan
  • 결측치를 임의로 삽입하면

1 cylinders 397 non-null float64

  • 데이터 정보가 float으로 바뀜.

+) 문자열은 결측치 있으면 object로 취급됨.

# 데이터프레임의 모든 열(숫자형, 문자열 등)을 포함
df.describe(include='all')
  • 한 번에 모든 통계값 체크.
df.count().values
# array([398, 398, 398, 398, 398, 398, 398, 398, 398])

df.count()가 어떤 의미의 series이자 딕셔너리므로, values 찍으면 배열이 나오게 됨.

import seaborn as sns

titanic= sns.load_dataset('titanic')

unique_values_ratio = (titanic['sex'].value_counts(normalize=True) *100).round(1)
unique_values_ratio
print(df.mean(numeric_only=True)) # 수치값이 있을 때는 numeric_only를 넣어야 한다.

상관계수와 비슷한데 단위가 있는 것 ⇒ 공분산.

🟢오픈 데이터와 데이터 윤리

포트폴리오는 팜플렛으로 만들지 말고, 문제 해결 과정을 작성해야 한다.

눈누 ⇒ 폰트 다운로드

  • 상업화하거나 웹에 띄울 때 조심해야한다.

바이브코딩…. 프론트엔드의 절망(남의 이야기가 아니게 될 수 있으니 힘내야 한다.)

Tableau, Power BI → indeed .

🟢그래프 실습

🔵여러 개를 그리고 싶으면 그래프를 객체로 선언하라!


# 그래프 객체 생성 (figure에 1개의 서브 플롯을 생성)
fig = plt.figure(figsize=(20, 5))   
ax = fig.add_subplot(1, 1, 1)

# axe 객체에 plot 함수로 그래프 출력
ax.plot(col_years, df_3.loc['충청남도',:], marker='o', markerfacecolor='green', 
        markersize=10, color='olive', linewidth=2, label='서울 -> 충남')
ax.plot(col_years, df_3.loc['경상북도',:], marker='o', markerfacecolor='blue', 
        markersize=10, color='skyblue', linewidth=2, label='서울 -> 경북')
ax.plot(col_years, df_3.loc['강원도',:], marker='o', markerfacecolor='red', 
        markersize=10, color='magenta', linewidth=2, label='서울 -> 강원')

🔵locals() 함수 활용하여 변수명 정리

url = "https://api.stock.naver.com/chart/domestic/item/{}/day?startDateTime=20240101&endDateTime=20260122"
code = { 'SK하이닉스' : '000660', '삼성전자' : '005930'}
for key, val in code.items():
    locals()[key]=pd.DataFrame(requests.get(url.format(val)).json())

→ 바로 데이터프레임을 키 값을 변수명으로 만들어서 사용하기.

a = 10
b = 20
print(locals())
#{'a': 10, 'b': 20}
key = 'SK하이닉스'
val = '000660'
SK하이닉스 = pd.DataFrame(...)
  • 즉, local 함수를 활용하여 딕셔너리의 키 값으로 데이터프레임을 생성할 수 있음.

오전 수업 요약

→ 각 다른 값을 쓸 때는 축을 따로 지정해서 나눌 수 있음

col_years = 삼성전자.localDate

col_years2 = pd.date_range('2024-01-01', '2026-01-23', freq='ME')
# 축 눈금 위치 지정
ax.set_xticks(col_years2)
  • x축 설정하기.
# 그래프 객체 생성 (figure에 1개의 서브 플롯을 생성)
fig = plt.figure(figsize=(70, 5))   
ax = fig.add_subplot(1, 1, 1)

# axe 객체에 plot 함수로 그래프 출력
ax.plot(col_years ,  삼성전자.closePrice, marker='o', markerfacecolor='green', 
        markersize=3, color='olive', linewidth=2, label='삼성전자')
# ax.plot( col_years, SK하이닉스.closePrice, marker='o', markerfacecolor='blue', 
#         markersize=3, color='skyblue', linewidth=2, label='SK하이닉스')

ax1 = ax.twinx()
ax1.plot( col_years, SK하이닉스.closePrice, marker='o', markerfacecolor='blue', 
        markersize=3, color='skyblue', linewidth=2, label='SK하이닉스')
  • 그래프 2개 만들기.
  • ax1 = ax.twinx()
    ⇒ x축 그대로 공유하고 y축 하나 더 만들겠다는 뜻.
profile
지루하게 선명하기보다는 흐릿해도 흥미롭게

0개의 댓글