在有15000条记录的pandas Dataframe 上循环非常慢,需要72秒

1tuwyuhd  于 2023-06-20  发布在  其他
关注(0)|答案(6)|浏览(81)

我有一个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')

我使用iloc上的for循环遍历DataFrame,并构建一个字典,其中列名作为字典的键,但名称不同。例如:

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循环不对任何列进行任何处理,除了更改dictionary的键值和使用if条件读取日期时间列。
为什么for循环需要72秒,而pandas库只需要4秒就可以读取相同数量的记录?
编辑1:
所需的输出或转换是字典对象列表。每个字典对象都有一个键:一行的所有列的值对。列表将具有与行数一样多的字典对象。
编辑2:
如果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中的列名不同。
这是一个坏的代码,我从以前的编码器继承。我的工作是在数据框架有几千行时提高速度。我不想在这一点上改变Web应用程序的前端和后端之间的契约,因为这将需要大量的更改。

h43kikqp

h43kikqp1#

尝试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}]
dgsult0t

dgsult0t2#

试试这个:

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}]
p1iqtdky

p1iqtdky3#

基于所提供的示例,也许您可以尝试使用列表解析。类似于:

[{'mycol1': str(val1), 'mycol2': str(val2), 'mycol3': str(val3)} for val1, val2, val3 in zip(df['Col 1'], df['Col B'], df['Col C'])]
gudnpqoy

gudnpqoy4#

我比较了Himanshu Panwar's solution的一个稍微修改的版本(为了符合OP的问题),使用列表理解(基于Anastasiya-Romanova's solution)和Corralien's solution

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
vvppvyoh

vvppvyoh5#

在Python中使用普通的for循环来处理大数据从来都不是一个好主意。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不是为这样的数据操作而设计的,但它可以工作。

3vpjnl9f

3vpjnl9f6#

尝试:

df.set_index('col1').to_dict('dict')

相关问题