본문으로 건너뛰기
김신건의 로그

[Pandas] read_json / to_json

· 수정 · 📖 약 2분 · 573자/단어 #python #pandas #io #json
Pandas read_json, Pandas to_json, JSON pandas

정의

pandas.read_json 은 JSON 문자열 또는 파일을 DataFrame 으로 변환. orient 파라미터가 핵심, JSON 의 구조가 어떤 형태인지를 선언한다.

반대 방향은 DataFrame.to_json : DataFrame 을 JSON 으로 직렬화.

사용 상황

상황권장
REST API 응답 (배열 of 객체)orient='records'
pandas 자체 직렬화 / 복원orient='split'
줄당 객체 (JSONL, 로그)lines=True
대용량 JSONL 스트리밍lines=True, chunksize=N
중첩 JSON 평탄화pd.json_normalize()

orient 옵션 한눈에 보기

orientJSON 구조설명
records[{col: val, ...}, ...]배열 of 객체, API 응답
columns{col: {idx: val}}기본값, 열 중심
index{idx: {col: val}}행 중심
split{columns:[...], index:[...], data:[ [...] ]}효율적, 메타 보존
tableJSON Table Schema 포함dtype 메타데이터 포함
values[[v1, v2], ...]헤더 없는 raw 2D
flowchart LR
    A["JSON 입력"] --> B{"orient 선택"}
    B -->|"records"| C["배열 of 객체"]
    B -->|"split"| D["효율적 직렬화"]
    B -->|"table"| E["dtype 메타 포함"]
    B -->|"values"| F["헤더 없는 raw"]
    C --> G["DataFrame"]
    D --> G
    E --> G
    F --> G

records: 가장 흔한 패턴

python
import pandas as pd
import io

json_text = '[{"name":"Alice","age":30},{"name":"Bob","age":25}]'
df = pd.read_json(io.StringIO(json_text), orient='records')
print(df)
print(df.dtypes)
결과
    name  age
0  Alice   30
1    Bob   25
name    object
age      int64
dtype: object

split: pandas 내부 직렬화

# 저장
df.to_json('snapshot.json', orient='split')
# 복원
df2 = pd.read_json('snapshot.json', orient='split')

split 포맷의 JSON 구조:

{
  "columns": ["name", "age"],
  "index": [0, 1],
  "data": [["Alice", 30], ["Bob", 25]]
}

columns / index 정보가 모두 보존되어 완전한 복원이 가능.

table: dtype 메타데이터 포함

df.to_json('typed.json', orient='table', indent=2)
df2 = pd.read_json('typed.json', orient='table')
# dtype 까지 복원됨 (orient='split' 은 dtype 복원 안 됨)

values: 헤더 없는 raw 배열

import io, pandas as pd

raw = '[[1, "Alice"], [2, "Bob"]]'
df = pd.read_json(io.StringIO(raw), orient='values')
df.columns = ['id', 'name']   # 컬럼명 직접 지정 필요

lines (JSONL) 처리

JSONL(JSON Lines) 은 각 줄이 독립적인 JSON 객체. 로그 파일, 데이터 익스포트에 흔함.

{"id":1,"name":"Alice"}
{"id":2,"name":"Bob"}
df = pd.read_json('data.jsonl', lines=True)

chunksize (대용량 JSONL 스트리밍)

total = 0
chunks_processed = 0

for chunk in pd.read_json('huge.jsonl', lines=True, chunksize=10_000):
    total += chunk['amount'].sum()
    chunks_processed += 1

print(f'청크 {chunks_processed} 개 처리, 총합: {total}')

메모리에 전체를 올리지 않고 10K 줄씩 처리.

중첩 JSON: json_normalize

깊이 있는 중첩 구조는 pd.json_normalize 가 강력.

python
import pandas as pd

data = [
  {'id': 1, 'name': 'Alice', 'address': {'city': 'Seoul', 'zip': '12345'}},
  {'id': 2, 'name': 'Bob',   'address': {'city': 'Busan', 'zip': '67890'}},
]
df = pd.json_normalize(data, sep='_')
print(df)
print(df.columns.tolist())
결과
   id   name address_city address_zip
0   1  Alice        Seoul       12345
1   2    Bob        Busan       67890
['id', 'name', 'address_city', 'address_zip']

중첩 객체가 sep 구분자로 연결된 컬럼으로 평탄화.

record_path: 배열 안의 배열

data = [
    {'user': 'Alice', 'orders': [{'id': 1, 'qty': 2}, {'id': 2, 'qty': 5}]},
    {'user': 'Bob',   'orders': [{'id': 3, 'qty': 1}]},
]
df = pd.json_normalize(
    data,
    record_path='orders',   # 배열 필드
    meta='user',            # 상위 필드를 컬럼으로
)
print(df)
#    id  qty   user
# 0   1    2  Alice
# 1   2    5  Alice
# 2   3    1    Bob

convert_dates (날짜 처리)

# ISO 8601 문자열 자동 파싱 시도
df = pd.read_json(path, orient='records', convert_dates=['created_at'])

# epoch ms → datetime
df = pd.read_json(path, convert_dates=True)   # 모든 숫자형 날짜 시도

# 날짜 파싱 비활성화
df = pd.read_json(path, convert_dates=False)

API 응답 처리

import requests

response = requests.get('https://api.example.com/users')
data = response.json()

# 방법 1: pd.read_json (문자열 경로)
import io, json
df = pd.read_json(io.StringIO(json.dumps(data)), orient='records')

# 방법 2: pd.DataFrame (더 명확, data 가 list of dict 이면)
df = pd.DataFrame(data)

to_json (저장)

# records 형태 (가장 일반적)
df.to_json('out.json', orient='records', force_ascii=False, indent=2)

# JSONL (한 줄 한 객체)
df.to_json('out.jsonl', orient='records', lines=True, force_ascii=False)

# 날짜 ISO 포맷
df.to_json('out.json', orient='records', date_format='iso', force_ascii=False)

# 문자열로 반환 (파일 아닌 메모리)
json_str = df.to_json(orient='records', force_ascii=False)

orient 별 to_json / read_json 왕복

for orient in ['records', 'split', 'index', 'columns', 'table']:
    buf = df.to_json(orient=orient)
    df2 = pd.read_json(buf, orient=orient)
    assert df.equals(df2), f'{orient} 왕복 실패'

table orient 는 dtype 까지 보존하므로 가장 완전한 직렬화.

함정

1. orient 기본값이 columns

pd.read_json('[{"a":1,"b":2}]')
# orient='columns' 기본 → 예상과 다른 결과

pd.read_json('[{"a":1,"b":2}]', orient='records')  # ✓ 명시

API 응답을 처리할 때 orient='records' 를 명시하지 않으면 컬럼이 뒤집힌 구조가 나온다.

2. 한글이 \u escape 로 저장

df.to_json('out.json')                         # 한글이 \uXXXX 로
df.to_json('out.json', force_ascii=False)      # ✓ 한글 그대로

3. 날짜가 epoch ms (숫자) 로 저장

df.to_json('out.json')                         # datetime → 정수 (ms)
df.to_json('out.json', date_format='iso')      # ✓ "2024-01-15T00:00:00"

4. 대용량 단일 파일 메모리 폭주

# ❌ 한 번에 로드
df = pd.read_json('10GB.jsonl', lines=True)

# ✓ 청크로
for chunk in pd.read_json('10GB.jsonl', lines=True, chunksize=100_000):
    process(chunk)

5. read_json 과 pd.DataFrame 차이

  • pd.read_json(path) : 파일/URL/문자열에서 직접 읽기, orient 파싱 포함
  • pd.DataFrame(list_of_dict) : 이미 파싱된 파이썬 객체에서 생성, 더 명확

API 응답처럼 이미 파이썬 객체로 파싱된 경우 pd.DataFrame(data) 가 더 직관적.

6. index orient 와 columns orient 혼동

# columns (기본): {컬럼명: {인덱스: 값}}
# index: {인덱스: {컬럼명: 값}}
# 둘 다 dict of dict 이지만 키 순서가 반대

참고

이 글의 용어 (5개)
[Pandas] DataFramepandas
정의 은 2차원 레이블 테이블. 각 열이 , 모든 열이 같은 (행 라벨) 를 공유. SQL 테이블 / Excel 시트 / R data.frame 의 Python 대응체. 구조 시…
[Pandas] dropna / fillnapandas
정의 - : NaN 이 있는 행/열 제거 - : NaN 을 특정 값으로 대체 데이터 분석의 가장 기본적인 결측치 처리. 사용 상황 - CSV 로드 후 빈 셀이 NaN 으로 읽혔을…
[Pandas] read_csv / to_csvpandas
정의 는 CSV(Comma-Separated Values) 또는 구분자 기반 텍스트 파일을 DataFrame 으로 읽는 함수. pandas 사용의 출발점. 반대 방향은 : Dat…
[Pandas] read_excel / to_excelpandas
정의 는 Excel 파일 (.xlsx, .xls) 을 으로 읽는 함수. 와 은 역방향 저장을 담당한다. 한국 실무에서 업무 보고서, 정산 파일, 외부 데이터 수신 등에 매우 자주…
[Pandas] read_parquet / to_parquetpandas
정의 Parquet 은 column-oriented binary 포맷. CSV 대비 수십 배 빠르고 작다. dtype 보존, 압축, 부분 컬럼 읽기 지원. 데이터 분석의 사실상 …

이 개념을 다룬 위키 페이지 (1)

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기