gpt4 book ai didi

python - Pandas 数据帧到对象实例数组的批量数据库插入效率

转载 作者:行者123 更新时间:2023-12-02 03:00:51 25 4
gpt4 key购买 nike

我有一个 Pandas 数据框,其形式为:

Time    Temperature    Voltage    Current
0.0 7.8 14 56
0.1 7.9 12 58
0.2 7.6 15 55
... So on for a few hundred thousand rows...

我需要尽快将数据批量插入 PostgreSQL 数据库。这是一个 Django 项目,我目前正在使用 ORM 进行数据库操作和构建查询,但如果有更有效的方法来完成任务,我愿意接受建议。

我的数据模型如下所示:

class Data(models.Model):
time = models.DateTimeField(db_index=True)
parameter = models.ForeignKey(Parameter, on_delete=models.CASCADE)
parameter_value = models.FloatField()

所以 Time 是 DataFrame 的 row[0],然后对于每个标题列,我获取与其对应的值,使用标题作为 参数。因此,示例表的 row[0] 将在我的数据库中生成 3 个 Data 对象:

Data(time=0.0, parameter="Temperature", parameter_value=7.8)
Data(time=0.0, parameter="Voltage", parameter_value=14)
Data(time=0.0, parameter="Current", parameter_value=56)

我们的应用程序允许用户解析以毫秒为单位的数据文件。因此,我们从单个文件生成大量单独的数据对象。我当前的任务是改进解析器,使其更加高效,直到我们达到硬件级别的 I/O 限制。

我当前的解决方案是遍历每一行,在时间+参数+值上为每一行创建一个Data对象,并将所述对象附加到一个数组中,这样我就可以Data.objects.bulk_create(all_data_objects) 通过 Django。当然我知道这是低效的,并且可能会得到很大的改进。

使用此代码:

# Convert DataFrame to dict
df_records = df.to_dict('records')

# Start empty dta array
all_data_objects = []

# Go through each row creating objects and appending to data array
for row in df_records:
for parameter, parameter_value in row.items():
if parameter != "Time":
all_data_objects.append(Data(
time=row["Time"],
parameter_value=parameter_value,
parameter=parameter))

# Commit data to Postgres DB
Data.objects.bulk_create(all_data)

当前整个操作,包括数据库插入操作(写入磁盘),即仅生成 Data 对象数组,对于生成的 55mb 文件大约 600 万个单独的 Data 对象大约需要 370 秒。仅 df_records = df.to_dict('records') 行就需要 83 秒左右。在每个部分的两端使用 time.time() 测量时间并计算差值。

我怎样才能改善这些时间?

最佳答案

如果您确实需要快速解决方案,我建议您直接使用pandas来简化表格。

首先让我们为您的示例创建数据:

import pandas as pd

data = {
'Time': {0: 0.0, 1: 0.1, 2: 0.2},
'Temperature': {0: 7.8, 1: 7.9, 2: 7.6},
'Voltage': {0: 14, 1: 12, 2: 15},
'Current': {0: 56, 1: 58, 2: 55}
}
df = pd.DataFrame(data)

现在您应该转换数据框,以便通过 melt 获得所需的列:

df = df.melt(["Time"], var_name="parameter", value_name="parameter_value")

此时,您应该将参数值映射到外部id。我将使用 params 作为示例:

params = {"Temperature": 1, "Voltage": 2, "Current": 3}
df["parameter"] = df["parameter"].map(params)

此时数据框将如下所示:

   Time  parameter  parameter_value
0 0.0 1 7.8
1 0.1 1 7.9
2 0.2 1 7.6
3 0.0 2 14.0
4 0.1 2 12.0
5 0.2 2 15.0
6 0.0 3 56.0
7 0.1 3 58.0
8 0.2 3 55.0

现在要使用pandas导出,您可以使用:

import sqlalchemy as sa
engine = sa.create_engine("use your connection data")
df.to_sql(name="my_table", con=engine, if_exists="append", index=False)

但是当我使用它时,它的速度不够快,无法满足我们的要求。所以我建议你使用 cursor.copy_from 安装,因为速度更快:

from io import StringIO

output = StringIO()
df.to_csv(output, sep=';', header=False, index=False, columns=df.columns)
output.getvalue()
# jump to start of stream
output.seek(0)

# Insert df into postgre
connection = engine.raw_connection()
with connection.cursor() as cursor:
cursor.copy_from(output, "my_table", sep=';', null="NULL", columns=(df.columns))
connection.commit()

我们尝试了数百万人,这是使用 PostgreSQL最快的方法

关于python - Pandas 数据帧到对象实例数组的批量数据库插入效率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60003621/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com