[Python] 추상적인 사고력이 중요한 이유
나는 자바로 개발을 시작했기 때문에…
데이터를 하나하나 반복문으로 직접 순회하고 조건을 걸며 처리하는 방식에 익숙하다.
for (int i = 0; i < arr.length; i++) {
if (arr[i] > 3) {
...
}
}
이게 익숙했고, 이게 명확하다고 느꼈다.
그런데 최근 배운 Numpy는 그 고정관념을 깨어주었다.
arr[arr > 3]
너무 짧고, 너무 간단해서 오히려 불편하다..
생각을 코드로 짠다는 느낌보다 전체적으로 계산을 한 뒤에 계산값을 조건으로 던진다는 느낌이었다.
자바에서는 내가 로직의 흐름을 제어한다.
조건문, 반복문, 변수 선언 등 모든 게 눈에 보인다.
반면 오늘 배운 넘파이는 데이터에 대한 조건만을 선언하기에 상당히 이해하기 힘들었다.
이해가 안되니 외워지지도 않았다…
movie[movie[:, 0] == 1][:, 2].mean()
이렇게 편리해보이는 코드도, 사실상 공책에다가 손으로 로직을 열심히 짜서
코드를 작성하였기때문에 어떻게보면 엄청난 추상화가 된 것을 알 수 있다.
로직을 다 짠후에 코드를 칠 때 조차
문법이 익숙하지 않아서 의심이 들었고, 그래서 중간 결과를 계속 찍어보며 확인했다.
### 무수한 의심...
movie_ids = np.unique(movie[:, 1])
print(movie_ids)
movie_rate = []
movie_mean = movie[movie[:, 1] == 1]
print(movie_mean)
movie_mean = movie_mean[:, 2]
print(movie_mean)
movie_mean = movie_mean.mean()
for movie_id in movie_ids:
movie_mean = movie[movie[:, 1] == movie_id][:, 2].mean()
movie_rate.append([movie_id, movie_mean])
print(movie_rate)
movie_ratings = np.array(movie_rate)
print(movie_ratings)
그 과정에서 깨달은 건,
넘파이는 단순히 짧은 게 아니라 데이터 전체를 단위로 처리하는 방식이라는 점이다.
이 과정이 익숙해진다면 대규모 데이터 처리에 특화되었다는게 무슨말인지 이해가 되지 않을까…
생각보다 잘 설계된 추상화
불리언 인덱싱, 슬라이싱, 타입 변환을 모두 한 줄에 담을 수 있다는 건
처음엔 부담이었지만, 조금만 익숙해지면 오히려 명확하게 의도를 표현할 수 있는 수단인 것 같다.
user_mean_arr[user_mean_arr[:, 1] >= 4][:, 0].astype(int)
이런 구문이 처음엔 낯설지만,
실제로는 “평균 평점이 4 이상인 사용자들의 ID만 정수형으로 뽑는다”는 명확한 뜻을 담고 있다.
결국 익숙하지 않았던 건 문법 자체가 아니라, 배열을 전체 단위로 사고하는 방식이었다.
자바와 넘파이의 구조적인 공통점
넘파이를 계속 이해하려고 노력하다 보니, 처음엔 몰랐던 자바와의 닮은 점도 보이기 시작했다.
넘파이 배열은 단순한 파이썬 리스트가 아니라, 고정 타입의 연속적인 메모리 블록이다.
이건 자바의 배열과 유사하다.
- 같은 타입만 저장 가능하고
- 메모리상에 인접하게 배치되어 있으며
- 슬라이싱 시에는 뷰(View)를 만들어 불필요한 복사를 피한다
결론적으로, 문법만 제대로 익힌다면 특정 조건에서 자바와 같은 사고 방식으로
더욱 간결하고 가독성 좋은 개발을 경험 할 수 있다는 뜻이다.
마무리…
넘파이.. 아직까지 너무 불편하다.
“왜 이렇게 쓰지?”라는 생각이 수시로 들었고, 여전히 자바식 사고에서 완전히 벗어나진 못했다.
그러나 회고를 하다보니
어느정도 넘파이가 문법적으로만 단축을 해둔게 아니라, 구조적으로 효율적이라는 걸 받아들이게 됐다.
추상화된 도구는, 결국 내가 할 수 있는 일을 더 빠르고 명확하게 해준다.
그걸 믿고, 천천히 따라가면 이 낯선 도구도 결국 내 손에 익게 된다는 걸 느낀 실습이었다.
Leave a comment