从数据库中提取相关数据



我有一个关于Python和数据库设计的问题。假设我有一个大型数据库(类似SQL的表格),有许多列(特征)和数百万行(记录)。

我想提取每条记录,其中有许多特征要一起处理。

这个数据库非常大,好像有数百万条记录和数万个特征。我目前正在做的是将每个单独的列提取到一个列表中,以便每个记录可以在不同的列表中使用相同的索引引用。
有更好的方法吗?我在想数据框架是否会更好?

作为一个例子,我正在处理3条记录(实际上有数百万条记录),以便我可以显示它们,就像在打印语句中一样:

namelist = ['Peter', 'John', 'Susan']
agelist = [16, 17, 18]
activitylist = ['play tennis', 'play chess', 'swim']
for i, name in enumerate(namelist):
print('Hi, my name is ' + name + '. I am ' + str(agelist[i]) + ' years old and I like to ' + activitylist[i])

输出:

Hi, my name is Peter. I am 16 years old and I like to play tennis  
Hi, my name is John. I am 17 years old and I like to play chess  
Hi, my name is Susan. I am 18 years old and I like to swim

我将使用下面的设置代码来详细说明我的答案,并用于时间测量。注意,数据框有300万条记录,作为示例,我选择了一个操作,将这些数据附加到一个变量中。

import pandas as pd
import time
namelist = ['Peter', 'John', 'Susan'] *1000000
agelist = [16, 17, 18] *1000000
activitylist = ['play tennis', 'play chess', 'swim'] *1000000
df = pd.DataFrame({'name': namelist, 'age': agelist, 'activity': activitylist})

您的原始方法已经非常有效,特别是如果数据很容易在单独的列表中出现,并且操作大约需要1.8秒在我的机器上:

start = time.time()
result = []
for i, name in enumerate(namelist):
result.append('Hi, my name is ' + name + '. I am ' + str(agelist[i]) + ' years old and I like to ' + activitylist[i])
end = time.time()
print(end - start)

输出:

1.7815442085266113

让我详细说明一下,如果数据来自这样的数据框架,可以使用一些替代方法:

df = pd.DataFrame({'name': namelist, 'age': agelist, 'activity': activitylist})

方法(1)使用df.iterrows()
这个方法逐行迭代,速度很慢。关于迭代的文档有一个警告框:

遍历pandas对象通常很慢。在许多情况下,不需要手动遍历行…

无论如何这个方法占用了112.3s在我的机器上:

start = time.time()
result = []
for i, row in df.iterrows():
result.append('Hi, my name is ' + row['name'] + '. I am ' + str(row['age']) + ' years old and I like to ' + row['activity'])
end = time.time()
print(end - start)

输出:

112.2983672618866

方法(2)使用df.to_numpy()
此方法逐行将数据帧转换为numpy数组,然后使用索引遍历每个数组。这是最接近您最初的列表操作。2.7秒在我的机器上:

start = time.time()
result = []
for row in df.to_numpy():
result.append('Hi, my name is ' + row[0] + '. I am ' + str(row[1]) + ' years old and I like to ' + row[2])
end = time.time()
print(end - start)

输出:

2.7370002269744873

方法(3)向量化
非向量化方法(如df.iterrows()df.apply())为每一行调用一个Python函数,并且该Python函数执行额外的操作。相比之下,这种向量化操作要快得多,因为它避免了在内部循环中使用Python代码。耗时约1.9秒在我的机器上:

start = time.time()
df.age = df.age.astype('str')
df['result'] = 'Hi, my name is ' + df.name + '. I am ' + df.age + ' years old and I like to ' + df.activity
result = df.result.tolist()
end = time.time()
print(end - start)

输出:

1.8785054683685303

方法(4)使用Zip进行列表推导
@Stuart建议的这个方法似乎是最快的!0.7s在我的机器上:

start = time.time()
result = [f'Hi, my name is {name}. I am {age} years old and I like to {activity}'
for name, age, activity in zip(namelist, agelist, activitylist)]
end = time.time()
print(end - start)

输出:

0.7034788322448731

最快的方法似乎是将列表压缩在一起,然后使用带格式字符串的列表推导式:

result = [f'Hi, my name is {name}. I am {age} years old and I like to {activity}'
for name, age, activity in zip(namelist, agelist, activitylist)]

矢量化的pandas方法(如@perpetualstudent的答案所示)似乎比这稍微慢一些,即使您可以将age存储为字符串,这样就不需要进行字符串转换。这显然是因为字符串操作不能像pandas中的数学运算那样通过向量化来加速。

最新更新