Правильный путь ™ для создания 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 на одном дыхании , чем это , чтобы создать пустой DataFrame (или один из из NaNs) и дополнения к нему снова и снова. Списки также занимают меньше памяти и представляют собой гораздо более легкую структуру данных для работы , добавления и удаления (при необходимости).
Другое преимущество этого метода заключается в том, что dtypes
они автоматически выводятся (а не присваиваются object
всем).
Последнее преимущество заключается в том, что для ваших данных автоматически создается aRangeIndex
, так что беспокоиться об этом будет меньше (взгляните на плохие методы 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
операций у вас есть. Соедините это с циклом, и вы получите квадратичную операцию сложности . Со df.append
страницы документа :
Итеративное добавление строк в DataFrame может быть более сложным в вычислительном отношении, чем одна конкатенация. Лучшее решение - добавить эти строки в список, а затем объединить список с исходным кадром данных сразу.
Другая ошибка, связанная с этим, df.append
заключается в том, что пользователи, как правило, забывают, что добавление не является функцией на месте , поэтому результат должен быть возвращен обратно. Вы также должны беспокоиться о dtypes:
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
Работа со столбцами объекта никогда не бывает хорошей, потому что pandas не может векторизовать операции над этими столбцами. Вам нужно будет сделать это, чтобы это исправить:
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
и даже более уродливо.
Пустой фрейм данных NaNs
И затем, создается DataFrame из NaN и все связанные с этим предостережения.
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
В приложении есть все вопросы, описанные выше.
for i, (a, b, c) in enumerate(some_function_that_yields_data()):
df.iloc[i] = [a, b, c]
Доказательство в пудинге
Сроки этих методов - самый быстрый способ узнать, насколько они различаются с точки зрения их памяти и полезности.
Контрольный код для справки.