콘텐츠로 이동

01. 리스트의 배신과 Array의 본질

"파이썬 리스트는 너무 똑똑해서, 오히려 단순 반복 노동(계산)에는 서툽니다."

우리가 지금까지 쓴 파이썬 리스트(List)는 만능 데이터 저장소였습니다. 숫자, 문자, 심지어 다른 리스트까지 다 담을 수 있었죠. 하지만 데이터가 수만, 수억 개가 되면 이 '유연함'이 독이 됩니다.

AI의 세계에서는 "같은 모양의 숫자 뭉치"를 엄청나게 빠르게 계산해야 합니다. 이때 리스트를 버리고 배열(Array)로 갈아타야 하는 이유를 알아봅니다.

1. 리스트 (List): 잡동사니 주머니

리스트는 마치 아무거나 다 들어가는 마법 주머니와 같습니다.

mymix = [10, "Hello", 3.14, [1, 2]]

이 코드는 개발자에겐 편리하지만, 컴퓨터(CPU)에겐 고역입니다.

  • 메모리 구조: 데이터가 메모리 공간 여기저기에 흩어져 있습니다. (비연속적 할당)
  • 비유: 보물찾기. 리스트의 다음 데이터를 찾으러면 쪽지(주소)를 보고 저~기 멀리 있는 메모리 주소로 뛰어가야 합니다.
  • 속도: 100만 개를 계산하려면 100만 번 뛰어다녀야 하니 느릴 수밖에 없습니다.
graph LR
    subgraph Memory["메모리 (Memory)"]
        direction LR
        L0["List[0]"] -.-> |주소 참조| D1["10 (int)"]
        L1["List[1]"] -.-> |주소 참조| D2["'Hello' (str)"]
        L2["List[2]"] -.-> |주소 참조| D3["3.14 (float)"]
    end
    style D1 fill:#f9f,stroke:#333
    style D2 fill:#ccf,stroke:#333
    style D3 fill:#ff9,stroke:#333

2. 배열 (Array): 잘 정돈된 탄약고

배열은 같은 종류의 물건만 빈틈없이 꽉 채워 넣은 상자입니다.

  • 특징:
    • Contiguous Memory (연속된 메모리): 데이터가 물리적으로 딱 붙어 있습니다.
    • Fixed Type (고정 타입): "여긴 전부 숫자(Int)만 들어있어!"라고 딱 정해져 있습니다.
  • 비유: 무빙워크. 가만히 서 있어도 데이터가 줄줄이 CPU로 들어옵니다. 보물찾기 할 필요가 없습니다.
  • 속도: 빛의 속도. 딥러닝이 가능한 이유가 바로 이 구조 때문입니다.
graph LR
    subgraph Array["배열 (Array)"]
        direction LR
        A0["10"] --- A1["20"] --- A2["30"] --- A3["40"]
    end
    style Array fill:#e1f5fe,stroke:#01579b
    style A0 fill:#b3e5fc,stroke:#0277bd
    style A1 fill:#b3e5fc,stroke:#0277bd
    style A2 fill:#b3e5fc,stroke:#0277bd
    style A3 fill:#b3e5fc,stroke:#0277bd

3. 왜 AI는 배열(Array)을 쓰는가?

AI 모델을 학습시킨다는 건 결국 수학(행렬 연산)을 하는 것입니다.

\[ y = wx + b \]

이 간단한 수식을 데이터 100만 개에 대해 동시에 계산해야 합니다.

  • 리스트 방식: for 문 돌면서 하나 계산하고, 다음 데이터 찾으러 갔다 오고... (세월아 네월아)
  • 배열 방식: "야, 여기 있는 100만 개 한꺼번에 다 곱해!" (CPU/GPU 병렬 처리 ⚡️)

설계자의 시선: Trade-off (등가교환)

컴퓨터 공학에 공짜는 없습니다. 하나를 얻으면 하나를 잃습니다.

구분 리스트 (List) 배열 (Array)
장점 유연함 (아무거나 다 담음) 속도 (엄청나게 빠름)
단점 느림 (메모리 파편화) 경직됨 (타입/크기 고정)

이제 우리는 유연한 '사용자 입장의 코딩'에서, 빠르고 효율적인 '설계자 입장의 코딩'으로 넘어갑니다. 그 시작이 바로 NumPy입니다.