这里的原始程序员。我的任务是清理以csv格式存储的医疗数据。
(请记住,当你读到这篇文章时,我只是一个初学者,所以感谢你的耐心(
一些快速背景:data1是一个csv,包含研究所需的患者(约17000名患者(。PUF_ED包含数百万患者的急诊科数据。对于数据1中的每个患者,我在PUF_ED中迭代,直到患者识别密钥(patient[0](与PUF_ED(I[0](中的识别密钥匹配,然后将患者数据重写到数据2中,PUF_ED的新数据附加到末尾。我知道panda的效率会高得多,但由于截止日期很严格,我没有时间学习panda并重写我所有的代码。我希望这里有人能帮我实现Cython。
import csv
def mortWriter():
puf_ed = open('PUF_ED.csv', 'r')
ed = csv.reader(puf_ed)
csv_data1 = open('data1.csv', 'r')
data1 = csv.reader(csv_data1)
csv_data2 = open('data2.csv', 'w')
data2 = csv.writer(csv_data2,
lineterminator='n')
patNum=0
for patient in data1:
if patNum==0:
data2.writerow(patient + ['EDDISP'])
patNum+=1
for i in ed:
if patient[0] == i[0]:
data2.writerow(patient + [i[12]])
break
puf_ed.seek(0)
puf_ed.close()
csv_data1.close()
csv_data2.close()
我试着在第一个for循环之前将patient和I变量键入整数,如下所示:
cdef int patient
cdef int i
但我收到错误:正在尝试索引非数组类型"int">
当我试图按照代码中所示对它们进行索引时。
我接下来应该采取什么步骤?非常感谢任何帮助我的人,我衷心感谢。
在拉出"大炮";并编写自定义cython代码或使用Panda,我想看看你是否可以首先改进基本python代码的算法。看看你的代码,你的mortWriter
函数是以下步骤(忽略patNum
那些没有意义的东西(:
for each patient in the study:
for each patient in the ED:
if ED patient happens to match study patient:
do_something()
这里有几件事会导致糟糕的性能:
- 在列表中查找对象是一项线性操作(也称为
O(n)
(,因为您必须一次搜索一名患者,直到找到目标患者。您可以使用set
或dict
来获得更快的恒定时间(也称为O(1)
(查找 - 您应该尽量避免重复从磁盘加载文件。这很慢。就速度而言,一般来说,CPU操作比内存(RAM(操作快得多,内存操作比磁盘/IO操作快得很多。一次又一次地重置ED文件并迭代是有问题的
- 一般来说,比起较小的列表,更喜欢重复迭代。在这种情况下,我不会为研究中的每一位患者查看整个急诊科,而是颠倒过程:为急诊科的每一个人,看看他们是否能在你的小研究集中找到。这可以与第2点相结合,因为更容易将较小的研究集存储在内存中
使用所有这些点,我得出了以下代码:
import csv
import math
import numpy as np
import time
def write_random_pat_csv(file_name, max_num_pats, num_data_cols=20, min_id=0, max_id=100_000, prefix="UH"):
num_pad_zeros = len(str(max_id - 1))
pat_ids = np.random.randint(min_id, max_id, max_num_pats)
pat_ids = np.unique(pat_ids)
num_pats = len(pat_ids)
pat_ids = [["UH" + str(i).zfill(num_pad_zeros)] for i in pat_ids]
pat_data = np.random.rand(num_pats, num_data_cols)
csv_file = open(file_name, "w")
csv_data = csv.writer(csv_file, lineterminator="n")
for i in range(num_pats):
csv_data.writerow(pat_ids[i] + list(pat_data[i]))
csv_file.close()
def generate_random_pat_files():
#num_study_pats = 17_000
#num_ed_pats = 10_000_000
num_study_pats = 170
num_ed_pats = 100000
write_random_pat_csv("data1.csv", num_study_pats)
write_random_pat_csv("PUF_ED.csv", num_ed_pats)
def mort_writer_slow():
puf_ed = open('PUF_ED.csv', 'r')
ed = csv.reader(puf_ed)
csv_data1 = open('data1.csv', 'r')
data1 = csv.reader(csv_data1)
csv_data2 = open('data2.csv', 'w')
data2 = csv.writer(csv_data2, lineterminator='n')
for patient in data1:
for i in ed:
if patient[0] == i[0]:
data2.writerow(patient + [i[12]])
break
puf_ed.seek(0)
puf_ed.close()
csv_data1.close()
csv_data2.close()
def mort_writer_fast():
puf_ed = open('PUF_ED.csv', 'r')
csv_data1 = open('data1.csv', 'r')
csv_data3 = open('data3.csv', 'w')
ed = csv.reader(puf_ed)
data1 = csv.reader(csv_data1)
data3 = csv.writer(csv_data3, lineterminator='n')
pat_num = 0
data1_pat_ids = set([row[0] for row in data1])
data1_rows = {pat_id: [] for pat_id in data1_pat_ids}
for i in ed:
pat_id = i[0]
if pat_id in data1_pat_ids:
data1_rows[pat_id].append([i[12]])
csv_data1.seek(0)
for i in data1:
pat_id = i[0]
rows = data1_rows[pat_id]
for row in rows:
data3.writerow(i + row)
puf_ed.close()
csv_data1.close()
csv_data3.close()
if __name__ == "__main__":
#pass
start = time.time()
generate_random_pat_files()
end = time.time()
print(end - start)
start = time.time()
mort_writer_slow()
end = time.time()
print(end - start)
start = time.time()
mort_writer_fast()
end = time.time()
print(end - start)
这比原始代码快50-100倍,至少在我尝试的较小数据集上是这样。