问题描述
我正在编写一个代码,该代码需要根据大表的每一行填充一组数据结构。现在,我正在使用熊猫读取数据并进行一些基本的数据验证预处理。但是,当我进入其余过程并将数据放入相应的数据结构中时,完成循环并填充我的数据结构需要花费很长时间。例如,在下面的代码中,我有一个包含15 M条记录的表。表有三列,我在每一行的基础上创建一个foo()对象,并将其添加到列表中。
# Profile.csv
# Index | Name | Family| DB
# ---------|------|-------|----------
# 0. | Jane | Doe | 08/23/1977
# ...
# 15000000 | Jhon | Doe | 01/01/2000
class foo():
def __init__(self,name,last,bd):
self.name = name
self.last = last
self.bd = bd
def populate(row,my_list):
my_list.append(foo(*row))
# reading the csv file and formatting the date column
df = pd.read_csv('Profile.csv')
df['DB'] = pd.to_datetime(df['DB'],'%Y-%m-%d')
# using apply to create an foo() object and add it to the list
my_list = []
gf.apply(populate,axis=1,args=(my_list,))
因此,在使用pandas将字符串date转换为date对象之后,我只需要遍历DataFrame来创建我的对象并将它们添加到列表中。这个过程非常耗时(在我的真实示例中,由于我的数据结构更复杂并且我拥有更多列,因此甚至花费更多时间)。因此,我想知道在这种情况下延长我的运行时间的最佳实践是什么。我是否应该甚至使用pandas
来读取我的大表并逐行处理它们?
解决方法
使用文件句柄会更快:
input_file = "profile.csv"
sep=";"
my_list = []
with open(input_file) as fh:
cols = {}
for i,col in enumerate(fh.readline().strip().split(sep)):
cols[col] = i
for line in fh:
line = line.strip().split(sep)
date = line[cols["DB"]].split("/")
date = [date[2],date[0],date[1]]
line[cols["DB"]] = "-".join(date)
populate(line,my_list)
,
针对这种情况有多种方法,但是,最快和最有效的方法是尽可能使用矢量化。我在本文中使用矢量化演示的示例的解决方案如下:
my_list = [foo(*args) for args in zip(df["Name"],df["Family"],df["BD"])]
如果无法进行矢量化,则将数据帧转换为字典可以显着提高性能。对于当前示例,if将类似于:
my_list = []
dc = df.to_dict()
for i,j in dc.items():
my_list.append(foo(dc["Name"][i],dc["Family"][i],dc["BD"][i]))
如果结构和过程的类型更加复杂,则最后一种解决方案特别有效。