У меня есть pandas DataFrame, содержащий 15000 записей и 20 столбцов, прочитанных из файла Excel. С использованием этого кода чтение файла Excel в DataFrame занимает около 4,13 секунды. Версия pandas в моей системе — 2.0.2.
df = pd.read_excel(excel_path, sheet_name='Sheet 1', header=[
2, 3]).astype(object).replace(np.nan, 'None')
Я перебираю DataFrame, используя цикл for поверх iloc и создаю словарь с именами столбцов в качестве ключей словаря, но с разными именами. Например:
data = []
for i in df.iloc:
mydict = {}
mydict['col1'] = i['Column 1 Name'].values[0]
mydict['col2'] = i['Column 2 Name'].values[0]
mydict['doc_date'] = datetime.datetime.strftime(i['Doc Details']['Doc Date'], r'%d-%m-%Y') \
if isinstance(i['Doc Details']['Doc Date'], datetime.datetime) \
else i['Doc Details']['Doc Date'].replace('/', '-')
# 17 more columns
data.append(mydict)
Цикл for занимает около 72 секунд.
Каков более быстрый способ зацикливания DataFrame и создания словаря? Цикл for не обрабатывает ни один из столбцов, кроме изменения имен ключей для словаря и использования условия if для чтения столбца даты и времени.
Почему цикл for должен занимать 72 секунды, когда такое же количество записей читается библиотекой pandas всего за 4 секунды?
РЕДАКТИРОВАТЬ 1:
Требуемый результат или преобразование — это список объектов словаря. Каждый объект словаря будет иметь пары ключ: значение для всех столбцов одной строки. В списке будет столько объектов словаря, сколько строк.
Обновлено еще раз:
Если мой Excel такой:
Col 1 Col B Col C
0 0 0
1 1 1
2 2 2
3 3 3
4 4 4
Мне нужен такой вывод:
[
{'mycol1': '0', 'mycol2': '0', 'mycol3': '0'
},
{'mycol1': '1', 'mycol2': '1', 'mycol3': '1'
},
{'mycol1': '2', 'mycol2': '2', 'mycol3': '2'
},
{'mycol1': '3', 'mycol2': '3', 'mycol3': '3'
},
{'mycol1': '4', 'mycol2': '4', 'mycol3': '4'
}
]
Обратите внимание, что каждый объект словаря имеет ключи столбцов, но с именами, отличными от имен столбцов в Excel.
Это плохой код, который я унаследовал от предыдущего кодера. Моя работа состоит в том, чтобы повысить скорость, когда фрейм данных содержит несколько тысяч строк. На данный момент я не хочу менять контракт между интерфейсом и серверной частью веб-приложения, потому что это потребует значительных изменений.
Потому что требуется иметь словарь для каждой строки. Это плохой код, который я унаследовал от предыдущего кодера. Моя работа заключается в повышении скорости. На данный момент я не хочу менять контракт между интерфейсом и серверной частью веб-приложения, потому что это потребует значительных изменений.
Вы пробовали df.to_dict('records')?






Пытаться:
df.set_index('col1').to_dict('dict')
Мне нужен список объектов словаря. В списке будет столько объектов словаря, сколько строк. Каждый объект словаря будет содержать пару ключ-значение для одной строки DataFrame. Я обновил свой вопрос, чтобы сделать его более понятным.
Попробуй это:
df=pd.DataFrame({'A':np.arange(5),'B':np.arange(5),'C':np.arange(5)})
print(df)
A B C
0 0 0 0
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
# Transpose the dataframe then create
list(df.T.to_dict().values())
[{'A': 0, 'B': 0, 'C': 0},
{'A': 1, 'B': 1, 'C': 1},
{'A': 2, 'B': 2, 'C': 2},
{'A': 3, 'B': 3, 'C': 3},
{'A': 4, 'B': 4, 'C': 4}]
Нет, я пытаюсь сделать это: [{'A': '0', 'B': '0', 'C': '0'}, {'A': '1', 'B': ' 1', 'C': '1'}, {'A': '2', 'B': '2', 'C': '2'}, {'A': '3', 'B' : '3', 'C': '3'}, {'A': '4', 'B': '4', 'C': '4'}]
Использование простых циклов for в python для обработки больших данных никогда не бывает хорошей идеей. Цикл for имеет много накладных расходов, которые замедляют обработку на несколько порядков.
Чтобы преобразовать DataFrame в dict, используйте встроенную функцию pandas to_dict(), что займет пару миллисекунд.
Выполните любые другие преобразования (например, обработку даты и времени) в DataFrame заранее. Преобразование в dict должно быть последним шагом.
Если вы хотите преобразовать свои данные так, как вы сказали в своем отредактированном сообщении, вы можете сделать:
d = {"mycol1":[0,1,2], "mycol2":[3,4,5]}
r = []
for i in range(len(list(d.values())[0])):
r.append(dict(zip(
list(d.keys()),
[a[i] for a in list(d.values())])
))
# returns [{'mycol1': 0, 'mycol2': 3}, {'mycol1': 1, 'mycol2': 4}, {'mycol1': 2, 'mycol2': 5}]
Это очень грязно, потому что dicts не созданы для такой манипуляции с данными, но это работает.
хорошо, но как мне получить список объектов словаря, как объяснено в моем отредактированном вопросе.
проверьте мой отредактированный ответ, решает ли это вашу проблему?
Основываясь на приведенном примере, возможно, вы можете попробовать использовать понимание списка. Что-то вроде:
[{'mycol1': str(val1), 'mycol2': str(val2), 'mycol3': str(val3)} for val1, val2, val3 in zip(df['Col 1'], df['Col B'], df['Col C'])]
Это тоже работает, но, узнав о df.to_dict('records'), я думаю, что это лучший подход для моих текущих требований.
Попробуйте df.to_dict('records'):
dmap = {'A': 'mycol1', 'B': 'mycol2', 'C': 'mycol3'}
out = df.rename(columns=dmap).to_dict('records')
Выход:
>>> out
[{'mycol1': 0, 'mycol2': 0, 'mycol3': 0},
{'mycol1': 1, 'mycol2': 1, 'mycol3': 1},
{'mycol1': 2, 'mycol2': 2, 'mycol3': 2},
{'mycol1': 3, 'mycol2': 3, 'mycol3': 3},
{'mycol1': 4, 'mycol2': 4, 'mycol3': 4}]
Спасибо. Это довольно аккуратный и чистый код. В моем фактическом коде, который я разместил в своем вопросе, у меня есть 2 строки заголовка - строки 2 и 3. Каким-то образом переименование не работает с использованием df.rename, если я передаю такой словарь: dmap = {'A': 'mycol1', 'B': 'mycol2', 'C': 'mycol3'} За исключением переименования столбца, вывод в желаемой структуре списка объектов словаря
Я опубликую отдельный вопрос о переименовании столбцов, когда файл Excel имеет несколько столбцов заголовков, и размещу ссылку на этот вопрос здесь. Спасибо!
@AllSolutions До чего это векторизованное решение сокращает время выполнения?
Я сравнил слегка модифицированную версию решения Химаншу Панвара (чтобы соответствовать тому, что было задано в вопросе ОП), с использованием понимания списка (на основе решения Анастасии-Романовой ) и решения Корральена:
import pandas as pd
import numpy as np
from time import perf_counter
df = pd.DataFrame({
'Col A': np.arange(5000),
'Col B': np.arange(5000),
'Col C': np.arange(5000),
})
print(df)
dmap = {'Col A': 'mycol1', 'Col B': 'mycol2', 'Col C': 'mycol3'}
new_names = ['mycol1', 'mycol2', 'mycol3']
#Himanshu Panwar's solution
t_start = perf_counter()
new_df1 = list(df.rename(columns=dmap).T.to_dict().values())
t_end = perf_counter()
Himanshu_Panwar_time = t_end-t_start
#List comprehension (Based on Anastasiya-Romanova's solution)
perf_counter()
new_df2 = [{new_names[ii]: value for ii, value in enumerate(row)} for row in zip(df['Col A'], df['Col B'], df['Col C'])]
t_end = perf_counter()
List_comprehension_time = t_end-t_start
#Corralien's solution
perf_counter()
new_df3 = df.rename(columns=dmap).to_dict('records')
t_end = perf_counter()
Corralien_time = t_end-t_start
print("\n", new_df1==new_df2==new_df3)
print("Himanshu Panwar's solution :", Himanshu_Panwar_time)
print("List comprehension (Based on Anastasiya-Romanova's solution) :", List_comprehension_time)
print("Corralien's solution :", Corralien_time)
Выходы:
Col A Col B Col C
0 0 0 0
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
... ... ... ...
4995 4995 4995 4995
4996 4996 4996 4996
4997 4997 4997 4997
4998 4998 4998 4998
4999 4999 4999 4999
[5000 rows x 3 columns]
True
Himanshu Panwar's solution : 0.3294021999463439
List comprehension (Based on Anastasiya-Romanova's solution) : 0.33864239999093115
Corralien's solution : 0.36161809996701777
Интересно, но самое быстрое решение не дает ожидаемого результата, а второе самое быстрое решение - больно писать на 20 столбцов (но это можно улучшить) :)
@Corralien Корральен Ты прав, я отредактировал свой ответ.
Почему
mydict = {}находится в петле? Вы уверены?