데이터 분석 기초

leave_a_comment·2026년 7월 27일

numpy 다루기

numpy 가 필요한 이유

  • Numerical Python의 줄임말로, 많은 양의 데이터를 반복문 없이 한 번에 계산하고 분석하기 위해 필요하다.
# 설치
uv add numpy 

# 라이브러리 불러오기
import numpy as np -> 가상 환경이 켜져 있어야 한다. .venv\Scripts\activate

배열 생성

  • axis=0 (1차원), axis=1 (2차원), axis=2 (3차원)
  • np.array(data) ㅡ 기존 data를 배열로 생성
  • np.zeros(shape) ㅡ shape에 맞는 모든 요소가 0인 배열 생성
  • np.ones(shape) ㅡ shape에 맞는 모든 요소가 1인 배열 생성
  • np.full(shape, value) ㅡ shape에 맞는 모든 요소가 value인 배열 생성
  • np.arrange(start, end, step) ㅡ 일정 간격의 연속된 숫자 배열 생성
  • np.linspace(start, end, num) ㅡ 지정한 개수로 균등 분할된 배열 생성
# 1차원 배열 
arr1 = np.array([1, 2, 3, 4, 5])
print(arr1)

# 2차원 배열
arr2 = np.array([
    [1, 2, 3, 4, 5],
    [6, 7, 8, 5, 2],
    [1, 5, 2, 3, 5]
])
print(arr2)

# 3차원 배열
arr3 = np.array([
    [
        [0, 255, 255], 
        [255, 255, 0] 
    ], 
    [
        [255, 0, 0], 
        [0, 0, 255]
    ]
])
print(arr3)
import numpy as np 

# 모든 값이 0인 배열을 생성(np.zeros(shape))
data1 = np.zeros((2, 3))
print(data1)

# 바깥부터 센다
data2 = np.ones((2,3,2))
print(data2)

# 내가 원하는 숫자
my_num = np.full((3, 2, 1), 999)
print(my_num)
# 연속적인 숫자 배열을 생성 -> np.arrange(start, end, step)

data3 = np.arange(0,10,2)
print(data3)

# 정해진 범위 안에 내가 지정한 개수만큼 배열 생성

# 실수로 반환한다.
data4 = np.linspace(1, 10, 4) # 마지막 숫자가 개수 (start 부터 end 까지 동일한 간격으로 num 개만큼 생성)
print(data4)

랜덤 배열 생성

  • np.random.rand(shape) ㅡ 0 이상 1 미만의 실수로 이루어진 배열 생성
  • np.random.randn(shape) ㅡ 평균 0, 표준편차 1의 정규분포 배열 생성
  • np.random.randint(low, high, shape) ㅡ 지정 범위의 정수로 이루어진 배열 생성
  • np.random.random(shape) ㅡ 0 이상 1 미만의 실수 배열 생성
import numpy as np

# np.random.rand(axis0, axis1, axis2)
# 0과 1사이의 실수 랜덤 배열 생성

# 튜플로 넣지 않고 두개 데이터 넘긴다
data1 = np.random.rand(2,3, 2) # 1차원 2차원 3차원
# print(data1)

# 평균이 0, 표준편차 1의 정규분포 배열 생성
# 0에 가까운 데이터 생성 해줘 (안정적)
data2 = np.random.randn(2,3)
print(data2)


# 지정 범위의 정수로 이루어진 배열 생성
# 시드를 고정하면 랜덤한 내용을 저장할 수 있다.
np.random.seed(123)

# data3 = np.random.randint(start, end, shape)
data3 = np.random.randint(0, 10, (2, 3))
print(data3)
arr2 = np.arange(0,10)
print(arr2)

# (1, 10), (2, 5), (5, 2), (10, 1)
arr2_reshpae = arr2.reshape(2, 5) #첫번쨰가 1이어도 위에와 다르다
print(arr2_reshpae)

배열 속성

  • 배열.shape ㅡ 배열의 각 차원 크기를 튜플로 표현
  • 배열.ndim ㅡ 배열이 몇 차원 데이터인지 나타냄
  • 배열.size ㅡ 배열에 포함된 전체 데이터 개수 의미
  • 배열.dtype ㅡ 배열에 저장된 데이터의 자료형 의미

배열 변환

  • 배열.reshape(shape) ㅡ 배열의 데이터는 유지하고 형태만 변경
  • 배열.flatten() ㅡ 다차원 배열을 1차원 배열로 변환
  • 배열.T or 배열.transpose() ㅡ 전치행렬(행렬 전환)

배열 연산

  • np.sum(배열) ㅡ 전체 합
  • np.mean(배열) ㅡ 평균
  • np.max(배열) ㅡ 최댓값
  • np.min(배열) ㅡ 최솟값
  • np.std(배열) ㅡ 표준편차
  • np.var(배열) ㅡ 분산
  • np.describe() ㅡ 위 내용들 한꺼번에 정리해서 보여줌
# 평균에 몰려있으면 분산, 표준편차가 작다. 
# 데이터가 제각각 흩어져 있으면 분산, 표준편차가 크다. 

# 최댓값이 어느 위치에 있나요? -> 인덱싱 쉽게 하기 위함 (값은 상관 없음)
np.argmax(data1)
# 최솟값이 어느 위치에 있나요?
np.argmin(data1)
data_2d = np.array([
    [10, 20, 30],
    [40, 50, 60]
])

# axis=0 분홍색 안에 있는 파란색을 더하라.
# print(np.sum(data_2d, axis=0))

# axis=1 파란색 안에 있는 요소를 더하라
# print(np.sum(data_2d, axis=1))




data_3d = np.array([
    [
        [255, 0, 0],
        [0, 255, 0]
    ],
    [
        [0, 0, 255],
        [255, 255, 0]
    ]
])

# axis=0 분홍색 안에 있는 파란색을 더하라.
print(np.sum(data_3d, axis=0))
print(" ")
# axis=1 파란색 안에 있는 요소를 더하라

노란색 위아래를 더해서 한 열,
두번째도 마찬가지로 더해서 한 열
print(np.sum(data_3d, axis=1))
print(" ")

한줄 한줄 더해서
# axis=2 노란색 안에 있는 요소를 더하라
print(np.sum(data_3d, axis=2))

이미지 데이터

# 이미지 불러오기 (uv add pillow)
from PIL import Image 
from IPython.display import display 

image = Image.open("./images/dog.jpg")
display(image)
import numpy as np
image_arr = np.array(image)
print(image_arr)

# 이렇게 해서 정사각형인지 아닌지도 판별이 가능하겠다.. h랑 w랑 개수 똑같이..
print(image_arr.shape)

# shape 는 (h,w,cㅡ채널 수(R,G,B))
# png는 RGBA(A는 투명도)


image_arr[:, :, 0] = 0
image2 = Image.fromarray(image_arr)
display(image2)
# 이렇게 하면 색 변경 불가한 화이트 보드 
white_board = np.full((200, 200), 255, dtype=np.uint8)

# 이렇게 하면 3차원 (색깔 변경 가능한 보드)
white_board_with_rgb = np.full((200, 200, 3), 255, dtype=np.uint8)

white1 = Image.fromarray(white_board)
display(white1)
white2 = Image.fromarray(white_board_with_rgb)
display(white2)

pandas 다루기

  • 데이터 분석에 관련된 기능을 제공하는 파이썬 라이브러리
  • csv, txt, excel 처리가 용이함
import pandas as pd

시리즈

  • 1차원 데이터 구조
  • 시리즈.index : 데이터의 위치와 기준을 나타내는 정보
  • 시리즈.values : 저장된 실제 데이터 값
  • 시리즈.dtype : 저장된 데이터의 자료형
  • 시리즈.name : 데이터의 의미 정보
  • 시리즈.size : 데이터의 개수
import pandas as pd
visitors = pd.Series(
    [120, 100, 30, 200, 80],
    name="일일 마트 방문자 수"
)
print(visitors)

print(visitors.index)
print(visitors.values)
print(visitors.dtype)
print(visitors.name)
print(visitors.size)

인덱스와 함께 생성

name_data = pd.Series(
    data=[24, 31, 26],
    index=["김영철","송윤지","임수현"],
    name="나이"
)
name_data

연산

# 크기가 다른 인덱스끼리 만나면 결측치가 발생한다.

data1 = pd.Series([1,2,3])
data2 = pd.Series([10,20,30])

# index가 0,1,2가 아니라 2,0,1로 변한다
data3 = pd.Series([10,20,30], index=[2,0,1])
data4 = pd.Series([10,20,30,40])


# 문자열과 숫자 연산은 불가능
# 데이터의 dtype을 바꾸는 메소드
data3_str = data3.astype(str)

결측치


# 결측치가 있기 때문에 float로 출력됨
print(data3+data4)
data1 = pd.Series(
    data=[10, 20, 30],
    index=["부산", "울산", "대구"]
)
print(data1)

data2 = pd.Series(
    data=[1, 2, 3, 4],
    index=["광주", "부산", "울산", "대구"]
)
print(data2)

print (" ")
add_data = data1 + data2
print(add_data)
print(add_data.isna()) # 결측치가 존재하는지 


print(add_data.fillna(1)) # 결측치를 1로 채운다
print(add_data.dropna()) # 결측치를 제거한다
import numpy as np
import pandas as pd

# np.nan -> 결측치 표시
data = pd.Series([1,2,np.nan, 4])
print(data)


# 결측치 유무 판별
print(data.isna())
print(data.isnull())


print("개수 :",data.isna().sum())

통계

data.sum()
data.min()
data.max()

# 한번에 알려줌
data.describe()

데이터프레임

  • 행과 열로 구성된 표 형태 데이터 구조
  • 여러개의 Series가 모여 이루어졌다
import pandas as pd
data_row_list = [
    {"이름": "김영철", "성별": "M", "나이": 24, "키": 179.4},
    {"이름": "송윤지", "성별": "F", "나이": 31, "키": 161.0},
    {"이름": "임수현", "성별": "F", "나이": 26, "키": 174}
]

df = pd.DataFrame(
    data=data_row_list, 
    columns=["이름", "성별", "나이", "키"]
)

데이터프레임 속성

  • 데이터프레임.index : 행의 위치와 기준을 나타내는 정보
  • 데이터프레임.columns : 각 열의 이름과 데이터 의미 정보
  • 데이터프레임.values : DataFrame에 저장된 실제 데이터 값
  • 데이터프레임.dtypes : 각 열별 데이터 타입 정보
  • 데이터프레임.shape : 행과 열의 개수를 튜플로 표현
  • 데이터프레임.size : 전체 데이터 요소 개수
  • 데이터프레임.ndim : 데이터가 몇 차원 구조인지 표현
# 데이터프레임에서 인덱스 설정하기
df.set_index("이름")
df.reset_index()

데이터프레임 조회 및 검색

# df.iloc[:, 열위치]


# 1번째에서 끝까지
df.iloc[:, 1:]


### 조회 3가지
### df[] 열 이름으로 조회 할 떄만
### df.loc[], df.iloc[]

# df.loc[행, 열]
# 이름으로 조회
# 1) 열 조회  df[열이름] / df.loc[:, 열이름]
df.loc[:, ["이름"]]
# 2) 행 조회 df.loc[행이름, :]
df.loc[0, :]
# 3) 셀 조회 df.loc[행이름, 열이름]
df.loc[0, "이름"]

# 위치로 조회 df.iloc[행, 열]
# 1) 열 조회 df.iloc[:, 열위치]
df.iloc[:, 0]
# 2) 행 조회 df.iloc[행위치, :]
df.iloc[0, 1:]
# 3) 셀 조회 df.iloc[행위치, 열위치]
df.iloc[0, 0]

조건부 조회

age_data3.loc[age_data3["이름"] == "김영철"]

# 송으로 시작해야 함
age_data3["이름"][1].startswith("송") 

### str 사용해야 함 !
age_data3["이름"].str.startswith("송") 
# age_data3.iloc[: , [0]]

# endswith
# contains
# 데이터 길이로 정제할 때 사용 .str.len()

# pandas에서는 기호로 작성
# 조건 2개 and, &
# 조건 또는 or, | 

데이터프레임 편집

  • reset_index() 인덱스를 열로 이동시킨다

  • 왜 필요한가? 조건으로 조회 후 인덱스가 연속되지 않기 떄문에 나중 조회에서 실수할 수 있다.

  • 초기화 해주는 게 좋다.

인덱스가 없는 데이터일 경우

age_data3.reset_index(drop=True) # index 열을 만들지 않는다.

병합

#예제 데이터
import pandas as pd
data1 = pd.DataFrame(
    data=[["강남", 1, 2], ["서초", 4, 5], ["노원", 5, 6]],
    columns=["지역명", "지점수", "매출"]
)
data1

data2 = pd.DataFrame(
    data=[["강남", 10, 20], ["도봉", 40, 50], ["노원", 50, 60]],
    columns=["지역명", "지점수", "매출"]
)
data2

data3 = pd.DataFrame(
    data=[["강남", 10, 20], ["도봉", 40, 50], ["노원", 50, 60]],
    columns=["지역명", "방문자수", "직원 수"]
)
data3


# 데이터 병합
import pandas as pd



how = left # df1에 있는 지역명만 정리할거다
how = right # df2에 있는 지역명만 정리할거다
inner는 둘다 있는 지역명만, outer는 있는 지역명 전부


total_data = pd.merge(
    left=data1,
    right=data2,
    how="outer", # left, right, inner, outer
    on="지역명" # 무엇을 기준으로 ?
)

total_data

total_data2 = pd.merge(
    left=data2,
    right=data3,
    how="inner",
    on="지역명"
)

total_data2

연산

# 데이터프레임 연산 : 행이름, 열이름이 같은 값끼리 연산된다. 
# 시리즈 연산 : 인덱스명이 같은 값끼리 연산된다. 
data1 + data2

데이터프레임 통계

# 결측치가 몇개 있는지
total_data.info()

# df.info(): 데이터 수(행 개수), 열 개수, 열 이름, 데이터 타입, 결측치 개수
# RangeIndex: 행 정보
# Data columns : 열 정보
# Non-null count : 결측치가 아닌 값 개수


# 데이터가 4개 있다 (4 entries)
# 5개의 열이 있다
# 지점수, 매출에 각각 1개의 결측치가 있다
# 열이 지점'수'인데 Dtype이 Str인지 아닌지 확인함으로써 이상한 데이터인지 확인

# 자리가 결측치인지 아닌지
total_data.isna()

total_data.isna().sum(axis=0) # axis=0 열별 결측치 개수 axis=1 행별 결측치 개수
total_data.describe()
total_data.describe(include=["string"]) # 범주형 데이터 (카테고리)

# 성별에 대한 요약이 unique(종류)=3 개이면 잘못된 데이터 임을 파악

데이터 불러오기


# 파일 불러오기
    # pd.read_csv(파일경로, 인코딩)
# txt 
# csv : 데이터가 쉼표로 구분되어 있다 -> 용량이 작다
# tsv : 데이터가 탭으로 구분되어 있다
# xls, xlsx 엑셀
profile
나도 성장하고파

0개의 댓글