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

판다스에 대해서 더 심화있게 들어가는줄 알았으나,

뒤로 갈수록 데이터를 가져오고, 정리하고, 다시 내가 쓰기 좋은 형태로 바꾸는 흐름이 좀 보였던 날이었다.

앞에서는 2차원 DataFrame 계속 만졌고, 뒤에서는 JSON이랑 API까지 갔다.

그래서 오늘은 “새로운 개념을 엄청 많이 배웠다” 느낌보다는, 앞에서 따로따로 보던 것들이

아 이렇게 연결되는구나 를 쫌 알게되었다 !


1. Series랑 DataFrame 차이가 오늘은 좀 제대로 보였다

예전에도 분명 배웠는데,

오늘 다시 보니까 좀 다르게 느껴졌다.

import pandas as pd

d = [1, 2, 3, 4, 5]
d_series = pd.Series(d)
d_df = pd.DataFrame(d)

전에는 그냥

Series는 1차원, DataFrame은 2차원

이렇게만 외웠던 것 같은데,

오늘은 진짜로

Series는 한 줄 느낌이고, DataFrame은 행/열이 있는 표 느낌으로 좀 들어왔다.

특히 Series는 .columns가 없고,DataFrame은 index, columns 둘 다 있다는 걸 보면서 아 이제부터는 그냥 몇 번째 값이 아니라몇 번째 행, 몇 번째 열인지를 같이 봐야 되는구나 싶었다.


2. DataFrame은 원소 하나씩보다 컬럼째로 보는 게 더 자연스러운 듯

오늘 컬럼 추가하고, 이름 바꾸고, 지우고 이런 걸 계속 했는데

그 과정에서 좀 느낀 게 있었다.

나는 아직도 뭘 보면

자꾸 원소 하나씩 접근하는 쪽으로 먼저 생각하게 되는데,

판다스는 그보다 컬럼 전체를 한 번에 다루는 쪽이 더 자연스러웠다.

예를 들면 이런 거:

d_df.columns = ["col1"]
d_df["new_col2"] = d
d_df["new_col3"] = 10
d_df["new"] = d_df["col1"] + d_df["new_col3"]

특히 마지막 줄.

d_df["new"] = d_df["col1"] + d_df["new_col3"]

이게 그냥 보면 별거 아닌데,

생각해보면 나는 아직도 이런 거 보면

for문 돌려서 더해야 하나?

이 생각이 먼저 날 때가 있다 ㅋㅋ

근데 오늘은

아 판다스에서는 이렇게 컬럼 자체가 계산되는구나

이게 좀 더 확실하게 들어왔다.


3. drop이랑 inplace가 은근 헷갈렸다

오늘 좀 걸렸던 건 drop()이었다.

d_df.drop("new", axis=1)
d_df.drop("new", axis=1, inplace=True)

처음엔 그냥 drop() 하면 지워지는 줄 알았는데 그게 아니라 기본은 보여주기만 하는 거였다. 진짜 반영하려면 inplace=True가 필요했다.

이거 은근 헷갈릴 듯…

그리고 axis도

머리로는 알겠는데 할 때마다 다시 보게 된다.

  • axis=0 → 가로줄
  • axis=1 → 세로줄

지금은 아는데

나중에 혼자 하다 보면 또 헷갈릴 가능성 높음 ㅋㅋ


4. reset_index가 왜 필요한지도 오늘 좀 체감했다

행 하나 지우고 나면

인덱스가 0, 1, 3, 4 이런 식으로 남는 것도 봤다.

처음엔

뭐 상관없지 않나?

싶었는데,

그 상태에서 그냥 막

for i in range(len(d_df)):
    print(d_df.at[i, "new0"])

이렇게 돌리면

실제 인덱스 2가 없어서 에러가 날 수 있었다.

그래서 reset_index()가 필요한 거였음.

이거 보고 좀 느낀 게

인덱스는 그냥 예쁘게 붙어 있는 번호가 아니라

진짜 접근 기준이라는 거였다.

예전엔 그냥 번호표 느낌이었는데,

오늘은

아 이거 꼬이면 나도 같이 꼬이는구나 싶었음.


5. 오늘 제일 중요했던 건 loc / iloc / at / iat 같음

이건 진짜 오늘 계속 나왔다.

솔직히 아직 완전 편한 건 아닌데,

그래도 전보단 좀 낫다.

내가 오늘 정리한 건 대충 이 정도다.

  • at, iat → 한 개 값 볼 때
  • loc, iloc → 여러 개도 가능
  • at, loc → 이름 기준
  • iat, iloc → 정수 기준

예시로는 이런 거 했다.

stock_price_df.iat[0, 0]
stock_price_df.at["2026-04-01", "시가"]
stock_price_df.loc["2026-04-03", ["시가", "종가"]]
stock_price_df.iloc[2, [0, 2]]

오늘 여기서 느낀 건

판다스는 값을 보기 전에 먼저

내가 정수로 갈 건지, 이름으로 갈 건지부터 정해야 한다는 거였다.

그냥 무작정 꺼내는 게 아니라

기준을 먼저 정해야 덜 헷갈리는 도구 느낌…


6. get_loc()도 생각보다 괜찮았다

처음엔 get_loc()이 좀 돌아가는 느낌이었는데

계속 보니까 이게 오히려 나중엔 더 편할 수도 있겠다는 생각이 들었다.

idx = stock_price_df.index.get_loc("2026-04-03")
cols = [
    stock_price_df.columns.get_loc("시가"),
    stock_price_df.columns.get_loc("고가")
]
stock_price_df.iloc[idx, cols]

이렇게 하면

  • 먼저 내가 원하는 위치를 찾고
  • 그다음 그 위치를 가지고 iloc로 접근

이 흐름이라서

컬럼 많아졌을 때는 오히려 구조가 더 잘 보일 것 같았다.

처음엔 귀찮아 보였는데

나중에 내가 코드 짤 때는 이런 식이 더 안정적일 수도 있겠다 싶었음.


7. apply + lambda는 확실히 편했다

오늘 좀 오… 했던 건 apply + lambda였다.

예를 들어 날짜별 변동성 구하는 거:

stock_price_df["Gap"] = stock_price_df.apply(
    lambda x: x.max() - x.min(), axis=1
)

이거 보면서 느낀 건

이건 진짜 코드를 짠다기보다

**“각 줄마다 내가 하고 싶은 규칙을 적는다”**는 느낌이라는 거였다.

  • 각 날짜 줄에 대해
  • 최고값과 최저값 차이를 구하고
  • 그걸 새 컬럼으로 넣는다

이 규칙이 그냥 코드에 바로 보이는 느낌.

근데 또 같이 들은 게

이게 편하고 읽기 좋은 대신

무조건 빠른 건 아니라는 점이었다.

큰 데이터에서는 느릴 수도 있고, 판다스 자체도 한계가 있다고.

그래서 약간 느낌이

  • 쓰기 편함
  • 읽기 좋음
  • 근데 성능은 또 따로 생각해야 됨

이런 느낌이었다.


8. 같은 걸 for문으로 다시 해본 것도 좋았다

좋았던 건

apply + lambda로 끝난 게 아니라 같은 걸 for문 + loc/at로도 다시 해봤다는 점이다.

cols = ["시가", "종가", "저가", "고가"]
new_col_name = "GapFor"
stock_price_df[new_col_name] = 0

for i in stock_price_df.index:
    data = stock_price_df.loc[i, cols]
    temp = data.max() - data.min()
    stock_price_df.at[i, new_col_name] = temp

이거 해보니까 차이가 좀 느껴졌다.

  • apply는 짧고 예쁨
  • for문은 길지만 구조가 더 잘 보임

나는 아직은

for문 쪽이 이해는 더 잘 된다 ㅋㅋ

apply는 멋있긴 한데, 아직은 한 번 더 생각하게 됨.


9. JSON은 딕셔너리처럼 생겼는데 바로 dict는 아니었다

후반에는 JSON도 봤다.

여기서 좀 헷갈렸던 게

생긴 건 딕셔너리 같아서

처음부터 바로 키값으로 접근될 것 같았다는 거다.

근데 실제로는 문자열이라서

그대로는 안 되고,

먼저 json.loads()로 바꿔야 했다.

import json

json_data1 = """{
    "color":"red",
    "value":"$100"
}"""

temp = json.loads(json_data1)
temp["color"]

이거 보고 나서야

아 JSON은 그냥 “딕셔너리처럼 생긴 텍스트”일 수 있구나

싶었다.


10. JSON은 depth 따라 하나씩 들어가야 했다

조금 더 복잡한 JSON은

리스트 안에 dict, 그 안에 또 리스트 이런 식이었다.

data["topping"][0]["id"]
data["groups"]["group"][1]["type"]

이 부분에서 느낀 건

JSON은 한 번에 못 가고

depth를 따라 하나씩 들어가야 한다는 거였다.

  • key로 들어가고
  • 리스트면 몇 번째인지 보고
  • 다시 key로 들어가고

처음엔 귀찮아 보였는데

구조가 보이면 또 규칙적이긴 했다.


11. API는 진짜 좀 재밌었다

오늘 제일 재밌었던 건 API였다.

그냥 파일 불러오는 게 아니라

웹에 있는 데이터를 공식적으로 요청해서 받아오는 방식이 나왔다.

오늘 예시는 영화진흥위원회 KOBIS API였다.

import pandas as pd
import urllib.request
import json

url_p1 = "<http://www.kobis.or.kr/kobisopenapi/webservice/rest/movie/searchMovieList.json>"
key = "내키"
url_p2 = str(50)

url = url_p1 + "?key=" + key + "&itemPerPage=" + url_p2

movie_page = urllib.request.urlopen(url)
movie_data = json.loads(movie_page.read().decode("utf-8"))

이거 보면서

아 데이터가 꼭 csv로만 있는 게 아니라

웹에 있고, 내가 요청해서 가져올 수도 있구나

이게 좀 더 실감났다.


12. 감독 정보 없을 때 에러 나는 것도 기억남

영화 정보 뽑다가

어떤 건 directors가 빈 리스트라서

[0] 접근할 때 에러가 났다.

그래서 이런 식으로 조건 처리했다.

if data["directors"] == []:
    i_dir = ""
else:
    i_dir = data["directors"][0]["peopleNm"]

이거 보면서 느낀 건

데이터 수집은 그냥 가져오면 끝이 아니라,

없는 값도 있을 수 있다는 걸 항상 생각해야 한다는 점이었다.

이게 파일 예제랑 실제 데이터 차이 같았음.


13. 결국 DataFrame으로 정리되는 흐름이 좀 좋았다

오늘 제일 좋았던 건

웹에서 받은 데이터도 결국

판다스로 정리된다는 흐름이었다.

tot_data = []

for idx, data in enumerate(movie_data["movieListResult"]["movieList"]):
    i_code = data["movieCd"]
    i_name = data["movieNm"]
    i_name_e = data["movieNmEn"]
    i_day = data["openDt"]

    if data["directors"] == []:
        i_dir = ""
    else:
        i_dir = data["directors"][0]["peopleNm"]

    tot_data.append([i_code, i_name, i_name_e, i_day, i_dir])

movie_df = pd.DataFrame(
    data=tot_data,
    columns=["moiveCd", "movieTitle", "MovieETitle", "openDay", "DirName"]
)

앞에서 배운 DataFrame이

그냥 예제 표가 아니라

실제로 웹에서 받은 데이터를 정리하는 도착지처럼 느껴졌다.


14. 후처리까지 가니까 진짜 데이터 다루는 느낌이 남

영화 데이터 받아서 끝나는 게 아니라

개봉일에서 year/month/day도 잘랐다.

movie_df["year"] = movie_df.loc[:, "openDay"].apply(lambda x: x[:4])
movie_df["month"] = movie_df.loc[:, "openDay"].apply(lambda x: x[4:6])
movie_df["day"] = movie_df.loc[:, "openDay"].apply(lambda x: x[6:])

그리고 movieCd가 유니크한지도 보고

인덱스로도 썼다.

len(movie_df.loc[:, "moiveCd"].unique()) == len(movie_df)
movie_df.set_index("moiveCd", inplace=True)

이 부분에서 좀 느낀 건

수집은 시작이고,

내가 쓰기 좋은 형태로 다시 바꾸는 게 진짜 작업이구나

이거였다.


15. 오늘 전체적으로 느낀 거

오늘은 진짜

“데이터 분석”이라는 게

그냥 표 보는 게 아니라는 걸 조금 더 느꼈다.

오늘 남은 건 대충 이런 거다.

  • DataFrame은 그냥 표가 아니라 2차원 자료구조
  • 값 접근은 기준부터 정해야 함
  • apply + lambda는 줄 단위 규칙 느낌
  • JSON은 텍스트일 수 있고, 바꿔야 접근 가능
  • API 데이터도 결국 DataFrame으로 연결됨

즉 오늘은

문법 하나를 깊게 판 날이라기보다,

데이터가 들어와서 → 정리되고 → 가공되고 → 내가 쓰는 구조가 되는 흐름이 좀 더 보였던 날 같았다.


마무리

10일차는

판다스만 한 날이라기보다,

  • 2차원 DataFrame 다루고
  • 값 접근하고
  • 줄 단위 계산하고
  • JSON 보고
  • API로 데이터 받고
  • 다시 DataFrame으로 정리하는

이 흐름이 이어진 날이었다.

오늘은 특히

“아 이래서 판다스를 쓰는구나”

가 조금 더 보였던 날.

앞으로는 그냥 코드만 보지 말고

이게 지금

  • 문자열인지
  • dict/list인지
  • DataFrame인지
  • 인덱스를 뭘로 잡아야 하는지

이걸 먼저 생각하면서 봐야겠다고 느낌 🌱