[SK플래닛] ASAC 빅데이터전문가 11기 | 09일차

앞 시간에는 최단거리 알고리즘 쪽으로 갔고, 뒤로 갈수록 데이터 분석을 실제로 어떻게 할 건지 쪽으로 무게가 넘어갔다.

그래서 하루 안에

  • 코딩테스트에서의 다익스트라
  • 데이터 분석 과정에서의 EDA / ML / DL / 인과관계
  • 그리고 그걸 실제로 받쳐주는 NumPy / Pandas

까지 한 번에 이어진 날이었다.

개인적으로는 오늘이

“아 이제 그냥 코테 문제만 푸는 단계는 아니구나”

이 느낌이 제일 크게 왔다.

파이썬으로 데이터를 가져오고, 가공하고, 보여주고,

그 다음에야 분석이나 예측으로 넘어간다는 흐름이 좀 더 선명해졌다.


1. 다익스트라 알고리즘: BFS에서 한 단계 일반화된 느낌

오늘 최단거리 파트에서 제일 먼저 정리된 건 이거였다.

기존 BFS 기반 최단거리 문제는

대부분 모든 간선의 가중치가 1이었다.

그래서 “먼저 도달한 경로 = 최단거리”로 처리할 수 있었다.

근데 다익스트라는 그게 안 된다.

왜냐면 가중치가 다 다르기 때문이다.

즉, 짧은 step 수가 짧은 거리 자체를 보장하지 않는다는 게 핵심이었다.

예를 들어 한 번에 가는 길보다, 여러 번 거쳐 가는 길이 총 비용은 더 짧을 수 있다.

그래서 여기서부터는 BFS처럼

“그냥 먼저 만난 애부터 처리”가 아니라,

  • 지금까지 알려진 거리 중 가장 짧은 노드
  • 그 노드를 기준으로 인접 노드 거리 갱신
  • 기존 값보다 짧으면 갱신

이 흐름으로 가야 했다.


내가 오늘 이해한 다익스트라 핵심

정리하면 이거다.

  1. 처음엔 모든 도시에 대해 inf로 세팅
  2. 출발점만 0으로 설정
  3. 현재까지 가장 짧은 거리의 도시를 선택
  4. 그 도시를 거쳐서 갈 수 있는 인접 도시들의 거리 계산
  5. 기존 거리보다 짧으면 갱신
  6. 이걸 반복

즉, 기존 BFS가

“인접하면 일단 간다”였다면,

다익스트라는

**“인접하더라도, 기존보다 짧을 때만 갱신한다”**가 핵심이다.


오늘 내 식으로 다시 써본 다익스트라 뼈대 코드

import heapq

INF = int(1e9)

def dijkstra(start, graph, n):
    distance = [INF] * (n + 1)
    distance[start] = 0

    q = []
    heapq.heappush(q, (0, start))  # (거리, 도시)

    while q:
        dist, now = heapq.heappop(q)

        # 이미 더 짧은 거리로 처리된 적 있으면 패스
        if distance[now] < dist:
            continue

        for nxt, cost in graph[now]:
            new_cost = dist + cost

            if new_cost < distance[nxt]:
                distance[nxt] = new_cost
                heapq.heappush(q, (new_cost, nxt))

    return distance

오늘 포인트는 코드 길이가 아니라

왜 (거리, 도시)를 같이 넣어야 하는지였다.

그냥 도시 번호만 넣으면

우선순위 큐가 무엇을 기준으로 우선 처리해야 하는지를 모른다.

그래서 거리 정보까지 같이 넣어야

가장 짧은 거리 기준으로 노드를 뽑을 수 있다.


여기서 내 시행착오

오늘 내가 여기서 제일 많이 느낀 건 이것들이었다.

1) 최단거리 = BFS라고 너무 빨리 생각했다

기존에 했던 특정 거리의 도시 찾기, 미로 탐색 같은 문제는

가중치가 전부 1이라 BFS가 자연스러웠다.

근데 오늘은 가중치가 달라졌다.

여기서도 BFS 감각으로 보면 바로 꼬인다.

즉, 최단거리라는 단어만 보고 같은 방식으로 가면 안 된다는 걸 다시 느낌.

가중치가 다르면 문제 자체가 달라진다.

2) “짧은 step”이 아니라 “짧은 거리”를 봐야 했다

이게 오늘 진짜 핵심이었다.

한 번에 가는 길이 있어도 비용이 크면 손해고,

두세 번 거쳐 가도 총 비용이 작으면 그게 최단거리다.

이 차이를 머리로는 알겠는데, 코드로 옮길 때는 자꾸 BFS식으로 생각하려고 했다.

3) 갱신 조건을 확실히 봐야 했다

이전엔 방문 안 했으면 그냥 넣는 문제를 많이 봤는데,

오늘은 그게 아니라

if new_cost < distance[nxt]:

이 비교가 핵심이었다.

즉, 이미 값이 있어도 더 짧으면 갈아끼운다.

이 감각이 오늘 중요한 포인트였다.


2. 이제부터는 “문제 푸는 파이썬”이 아니라 “데이터 다루는 파이썬”

오늘 뒤쪽에서 방향이 확 바뀌었다.

이제는 단순히 코테용 파이썬이 아니라,

내가 원하는 데이터를 가져오고, 가공하고, 결과를 보여주는 파이썬으로 넘어간다는 얘기가 나왔다.

즉, 데이터 분석 전체 흐름을 이렇게 잡는 거다.

  • 데이터 수집
  • 데이터 가공 / 전처리
  • 시각화
  • EDA
  • 필요하면 ML / DL
  • 나중에는 설명이나 인과추론까지

이 흐름 자체가 오늘 제일 크게 남았다.


EDA, ML, DL을 오늘 기준으로 정리하면

오늘 내가 이해한 건 이렇다.

EDA

일단 현상을 보는 단계다.

데이터가 어떻게 생겼고, 어떤 패턴이 있고, 뭘 더 보고 싶은지를 확인하는 단계.

ML

예측 모델로 넘어가고 싶을 때 쓰는 단계.

여기서는 특히 feature가 중요하고, 그래서 EDA가 기반이 된다.

DL

딥러닝도 예측은 하지만,

EDA보다 모델 구조 / 어떤 모델을 쓰는지 / 튜닝이 더 중요해진다.

한계

ML/DL은 예측은 해주는데

“그래서 왜 그런가?”를 명확하게 설명하는 데는 약점이 있다.

즉, 인과관계 설명이 부족하다는 점도 같이 나왔다.

이 부분이 되게 와닿았다.

예측은 잘 나오는데,

실제로 서비스나 매출을 개선하려면

“무엇을 늘리고 줄여야 하는가?”까지 말할 수 있어야 하니까.


오늘 느낀 데이터 분석 쪽 포인트

오늘 여기서 제일 크게 남은 건 두 가지였다.

1) 결국 내 데이터로 해봐야 한다

이미 있는 공공 데이터셋만 쓰면 편하긴 하다.

근데 그건 “문제 설정”의 흔적이 약하다.

오늘 수업에서는

본인이 직접 확인하고 싶은 주제를 정하고, 그걸 위한 데이터를 직접 찾아보고, 수집하고, 가공하는 과정 자체가 중요하다는 얘기가 나왔다.

2) 코드 핸들링이 자유로워야 한다

계속 찾아보면서 겨우겨우 붙이면 돌아갈 수는 있다.

근데 그러면 나중에 조금만 바뀌어도 다시 막힌다.

즉,

데이터 핸들링은 결국 손에 붙어 있어야 한다는 말이 오늘 좀 세게 남았다.


3. NumPy: “벡터 연산”이라는 말을 오늘 좀 제대로 이해함

오늘 NumPy에서 제일 크게 남은 건

이게 그냥 패키지가 아니라

파이썬에서 수치 연산을 편하게 하려고 만든 기반이라는 점이었다.

NumPy의 핵심 자료형은 array고,

이 array는 벡터 연산을 기본으로 깔고 간다.


왜 NumPy가 필요했는가

기존 파이썬 리스트도 값을 모아둘 수는 있다.

근데 리스트는 이런 게 안 된다.

a = [100, 200, 300]
a + 5

이런 식으로 모든 원소에 5를 한 번에 더하는 벡터 연산은 안 된다.

반면 NumPy array는 된다.

import numpy as np

a = np.array([100, 200, 300, 400, 500])
print(a + 5)
# [105 205 305 405 505]

즉, 기존에는

내가 직접 원소를 하나씩 돌면서 계산해야 했던 걸,

NumPy는 기능 중심으로 한 번에 표현할 수 있게 해준다는 점이 핵심이었다.

이게 오늘 제일 큰 차이로 느껴졌다.


오늘 정리한 NumPy 기본들

1) np.array()

리스트를 NumPy 배열로 바꾼다.

import numpy as np

a = [100, 200, 300, 400, 500]
a_arr = np.array(a)

print(a_arr)
print(a_arr + 5)

2) 벡터끼리 연산

같은 길이의 배열끼리는 원소별 연산이 된다.

x = np.array([1, 2, 3, 4, 5])
y = np.array([10, 20, 30, 40, 50])

print(x + y)
# [11 22 33 44 55]

3) np.arange()

규칙적인 숫자 생성에 편하다.

print(np.arange(0, 51, 10))
# [ 0 10 20 30 40 50 ]

4) [:, np.newaxis]

차원을 하나 늘릴 수 있다.

a = np.arange(0, 51, 10)[:, np.newaxis] + np.arange(0, 6, 1)
print(a)

이건 처음엔 살짝 낯설었는데,

결국 1차원 배열을 2차원처럼 확장해서 계산하기 위한 장치라고 이해하니까 조금 나아졌다.

5) shape / ndim / dtype

배열이 지금 몇 차원이고, 모양이 어떻고, 자료형이 뭔지 바로 확인 가능하다.

arr = np.array([[1, 2, 3], [4, 5, 6]])

print(arr.ndim)   # 차원
print(arr.shape)  # 모양
print(arr.dtype)  # 자료형

6) 불리언 인덱싱

이건 오늘 꽤 인상 깊었다.

arr = np.array([1, 3, 5, 7, 9])
print(arr[arr < 5])
# [1 3]

즉, 조건식을 인덱스 자리에 넣어서 필터링할 수 있다.

나중에 데이터 필터링이랑 연결될 거라서 이 부분이 되게 중요해 보였다.


내 시행착오: NumPy 파트

1) 처음엔 리스트랑 뭐가 다른지 감이 잘 안 왔다

겉으로는 리스트랑 비슷해 보인다.

근데 실제 차이는 벡터 연산이었다.

2) np.newaxis는 아직도 직관적이지는 않다

그냥 외우는 건 별로고,

“축 하나를 추가해서 차원을 늘린다”는 감각으로 보는 게 맞는 것 같다.

3) 2차원 접근은 파이썬 리스트랑 다르다는 걸 다시 느낌

리스트는 a[가로][세로]로 갔는데, NumPy는 a[가로, 세로]도 된다.

이런 차이들이 조금씩 쌓이면

나중에 데이터 핸들링에서 꽤 차이를 만들 것 같다.


4. Pandas: 왜 굳이 “내 인덱스”가 필요한지 조금 이해함

오늘 Pandas 파트에서 제일 크게 남은 건

이 패키지가 단순히 표처럼 보이는 도구가 아니라

**“정수 인덱스 말고, 내가 만든 기준으로 접근할 수 있게 해주는 도구”**라는 점이었다.

즉,

파이썬 리스트나 NumPy는 기본적으로 정수 인덱스가 중심인데,

Pandas는 여기서 한 걸음 더 나가서

내가 만든 인덱스 자체를 데이터 접근 기준으로 쓴다는 게 핵심이었다.


오늘 정리한 Pandas 기본

1) Series

1차원 데이터.

import pandas as pd

stock_price_series = pd.Series([213500, 22000, 200000, 195000, 214500])
print(stock_price_series)

2) 내가 만든 인덱스 붙이기

이게 오늘 핵심이었다.

import pandas as pd

stock_price_series_index = pd.Series(
    data=[213500, 22000, 200000, 195000, 214500],
    index=["2026-04-01", "2026-04-02", "2026-04-03", "2026-04-04", "2026-04-05"]
)

print(stock_price_series_index["2026-04-03"])

이제는 “몇 번째 값”이 아니라

내가 지정한 날짜로 바로 접근할 수 있다.

이게 리스트랑 가장 크게 달랐다.

3) 결측치 확인

인덱스를 맞춰 붙이다 보면 없는 값이 생길 수도 있다.

temp = pd.Series(data={"AAPL": 1000, "MS": 2000, "TSLA": 3000},
                 index=["GOOGLE", "AAPL", "MS", "META"])

print(temp[temp.isnull()])
print(temp[temp.notnull()])

이 부분은

나중에 실제 데이터 다룰 때 꽤 자주 쓸 것 같았다.


내 시행착오: Pandas 파트

1) “왜 굳이 인덱스를 또 만들지?” 싶었다

처음엔 그냥 0, 1, 2, 3으로도 충분해 보였다.

근데 실제 데이터는

“지난주 목요일 가격”, “특정 날짜”, “특정 티커”처럼

의미 있는 기준으로 접근하는 경우가 더 많다.

그래서 내 인덱스를 만든다는 개념이 Pandas의 존재 이유에 더 가깝다는 걸 오늘 좀 이해했다.

2) NumPy 다음 Pandas가 왜 나오는지도 조금 납득됐다

Pandas가 뜬금없이 나온 게 아니라,

NumPy의 array가 기반이고 그 위에서

데이터프레임/시리즈 같은 더 편한 형태를 제공하는 구조였다.


5. 오늘 개인적으로 남은 것

오늘은 단순히 “새 문법 몇 개 배웠다” 느낌은 아니었다.

오히려 이게 더 컸다.

1) 최단거리도 조건이 달라지면 완전히 다른 문제가 된다

BFS에서 하던 감각이

가중치가 들어가자마자 바로 안 통했다.

2) 데이터 분석은 결국 핸들링 자유도가 핵심이다

예쁜 시각화나 모델도 중요하지만,

그 전에 가져오고 / 가공하고 / 바꾸고 / 다시 보는 작업이 손에 붙어 있어야 한다는 말이 제일 현실적으로 와닿았다.

3) NumPy와 Pandas는 그냥 라이브러리가 아니라 사고방식이 다르다

기존엔 원소 하나하나를 돌리는 생각을 많이 했는데,

이제는 벡터 단위 / 줄 단위 / 컬럼 단위 / 기능 중심으로 생각해야 한다는 느낌이 들었다.


마무리

오늘은 앞에서는 다익스트라로

“최단거리 문제를 어떻게 더 일반화해서 보는지”를 배웠고,

뒤에서는 NumPy와 Pandas로

“이제 파이썬을 데이터 분석 쪽으로 어떻게 써야 하는지”를 배운 날이었다.

특히 나는 오늘

문법 자체보다 관점이 바뀐 날 같았다.

  • 코테에서는 “짧은 step”이 아니라 “짧은 거리”를 봐야 했고
  • 데이터 분석에서는 “원소 하나”가 아니라 “벡터/컬럼 단위 기능”으로 생각해야 했다

아직 손에 완전히 붙지는 않았지만,

그래도 방향은 확실히 보인 하루였다 !!

앞으로도 화이이티이이이잉 ~