DataFrame을 만드는 올바른 방법
TLDR; (굵은 글씨를 읽으십시오)
여기에있는 대부분의 답변은 빈 DataFrame을 만들고 채우는 방법을 알려주지 만 나쁜 일이라고 말하는 사람은 없습니다.
여기 내 조언이 있습니다 : 작업 할 데이터가 모두 준비 될 때까지 기다리십시오. 목록을 사용하여 데이터를 수집 한 다음 준비가되면 DataFrame을 초기화하십시오.
data = []
for a, b, c in some_function_that_yields_data():
data.append([a, b, c])
df = pd.DataFrame(data, columns=['A', 'B', 'C'])
빈 DataFrame (또는 NaN 중 하나)을 만들고 반복해서 추가하는 것보다 목록에 추가하고 한 번에 DataFrame을 만드는 것이 항상 저렴 합니다. 또한 목록은 메모리를 덜 차지하며 작업하기에 훨씬 가벼운 데이터 구조입니다. , 추가 및 제거 (필요한 경우)에 입니다.
이 방법의 다른 장점은 할당하는 대신 dtypes
자동으로 유추됩니다object
.
마지막 장점은 데이터에 대해 a RangeIndex
가 자동으로 생성 되므로 걱정할 필요가 없다는 것입니다 (아래 의 가난한 방법 append
과 loc
방법을 살펴보면 인덱스를 적절하게 처리 해야하는 요소가 모두 표시됩니다).
하지 말아야 할 것들
append
또는 concat
루프 내부
초보자에게서 본 가장 큰 실수는 다음과 같습니다.
df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
df = df.append({'A': i, 'B': b, 'C': c}, ignore_index=True) # yuck
# or similarly,
# df = pd.concat([df, pd.Series({'A': i, 'B': b, 'C': c})], ignore_index=True)
모든 작업 append
또는 concat
작업에 대해 메모리가 다시 할당됩니다 . 이것을 루프와 결합하면 2 차 복잡도 연산이 됩니다. 로부터 df.append
문서 페이지 :
반복적으로 DataFrame에 행을 추가하면 단일 연결보다 계산 집약적 일 수 있습니다. 더 나은 해결책은 해당 행을 목록에 추가 한 다음 목록을 원래 DataFrame과 한 번에 연결하는 것입니다.
또 다른 실수 df.append
는 사용자 가 추가 기능 을 잊어 버리는 경향이 있다는 점 입니다. 결과는 내부 기능 이 아니므로 결과를 다시 할당해야합니다. 또한 dtype에 대해 걱정해야합니다.
df = pd.DataFrame(columns=['A', 'B', 'C'])
df = df.append({'A': 1, 'B': 12.3, 'C': 'xyz'}, ignore_index=True)
df.dtypes
A object # yuck!
B float64
C object
dtype: object
팬더는 해당 열에 대한 연산을 벡터화 할 수 없으므로 객체 열을 다루는 것은 결코 좋은 일이 아닙니다. 수정하려면 다음을 수행해야합니다.
df.infer_objects().dtypes
A int64
B float64
C object
dtype: object
loc
루프 내부
또한 loc
비어있는 DataFrame에 추가하는 데 사용되는 것을 보았습니다 .
df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
df.loc[len(df)] = [a, b, c]
이전과 같이 매번 필요한 메모리 양을 미리 할당하지 않았으므로 새 행을 만들 때마다 메모리가 다시 증가합니다 . 그것은만큼 나쁘다append
더 추악합니다.
NaN의 빈 데이터 프레임
그리고 NaN의 DataFrame과 이와 관련된 모든 경고가 생성됩니다.
df = pd.DataFrame(columns=['A', 'B', 'C'], index=range(5))
df
A B C
0 NaN NaN NaN
1 NaN NaN NaN
2 NaN NaN NaN
3 NaN NaN NaN
4 NaN NaN NaN
다른 것과 같이 객체 열의 DataFrame을 만듭니다.
df.dtypes
A object # you DON'T want this
B object
C object
dtype: object
Appending은 여전히 위의 방법으로 모든 문제가 있습니다.
for i, (a, b, c) in enumerate(some_function_that_yields_data()):
df.iloc[i] = [a, b, c]
증명은 푸딩에 있습니다.
이러한 방법의 타이밍은 메모리와 유틸리티 측면에서 얼마나 다른지 확인할 수있는 가장 빠른 방법입니다.
참조를위한 벤치마킹 코드.