【问题标题】:How to insert arrays into a database?如何将数组插入数据库?
【发布时间】:2011-04-13 21:19:40
【问题描述】:

In my previous question 很多用户希望我提供更多数据来玩弄。所以我开始导出我的所有数据并用 Python 处理它,但后来我意识到:我应该把所有这些数据放在哪里?

好吧,我决定最好的办法是将它们保存在数据库中,这样至少我不会每次都有to parse the raw files。但由于我对数据库一无所知,这变得相当混乱。我尝试了一些教程来创建一个 sqlite 数据库,添加一个表和字段并尝试插入我的 numpy.arrays,但它无法让它工作。

通常情况下,我每只狗的结果如下所示:

所以我有 35 只不同的狗,每只狗都有 24 次测量值。每个测量本身都有未知数量的接触。每次测量都包含一个 3D 阵列(整个板的 248 帧 [255x63])和一个 2D 阵列(板 [255x63] 的每个传感器的最大值)。在数据库中存储一个值不是问题,但将我的 2D 数组放入其中似乎不起作用。

所以我的问题是我应该如何在数据库中排序并将我的数组插入其中?

【问题讨论】:

  • 为了全面披露,现在SuperUser Chat 正在讨论这个问题:-)
  • 主要原因是我不会成为使用它的人,我需要保证我的文件在我放置它们的位置。另外,显然我将插入更多数据,而不仅仅是这些数组。但是数组让我很头疼,所以如果我能把它们放进去,剩下的就容易了
  • 为什么不使用 pickle.dump 或 numpy.dump 呢?然后你可以直接转储你的多维数组。如果您只是将它用于 python 对象的持久性,那么没有理由设计数据库。

标签: python database-design numpy


【解决方案1】:

您可能希望从一个 dogs 表开始,其中包含每只狗的所有平面(非数组)数据,每只狗都有一个的东西,比如名字,性别和年龄:

CREATE TABLE `dogs` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `name` VARCHAR(64),
  `age` INT UNSIGNED,
  `sex` ENUM('Male','Female')
);

从那里开始,每只狗“有很多”测量值,因此您需要一个 dog_mesaurements 表来存储 24 个测量值:

CREATE TABLE `dog_measurements` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `dog_id` INT UNSIGNED NOT NULL,
  `paw` ENUM ('Front Left','Front Right','Rear Left','Rear Right'),
  `taken_at` DATETIME NOT NULL
);

然后,每当您进行测量时,您 INSERT INTO dog_measurements (dog_id,taken_at) VALUES (*?*, NOW()); 其中 * ? * 是 dogs 表中的狗的 ID。

然后您需要表格来存储每次测量的实际帧数,例如:

CREATE TABLE `dog_measurement_data` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `dog_measurement_id` INT UNSIGNED NOT NULL,
  `frame` INT UNSIGNED,
  `sensor_row` INT UNSIGNED,
  `sensor_col` INT UNSIGNED,
  `value` NUMBER
);

这样,对于 250 帧中的每一帧,您循环遍历 63 个传感器中的每一个,并将该传感器的值与帧号一起存储到数据库中:

INSERT INTO `dog_measurement_data` (`dog_measurement_id`,`frame`,`sensor_row`,`sensor_col`,`value`) VALUES
(*measurement_id?*, *frame_number?*, *sensor_row?*, *sensor_col?*, *value?*)

显然用实际值替换 measurement_id?frame_number?sensor_number?value? :-)

所以基本上,每个dog_measurement_data 都是给定帧的单个传感器值。这样,要获取所有给定帧的所有传感器值,您将:

SELECT `sensor_row`,sensor_col`,`value` FROM `dog_measurement_data`
WHERE `dog_measurement_id`=*some measurement id* AND `frame`=*some frame number*
ORDER BY `sensor_row`,`sensor_col`

这将为您提供该帧的所有行和列。

【讨论】:

  • 不过,对于“爪子”,您可能想要更通用的说法,即“附件”。那么你也可以让它成为大型蛛形纲动物、十足动物、虫族等的无符号整数......
  • @Tyler:总的来说,这是个好建议。在这种情况下,Ivo 正在开发专门用于狗的软件,但谁知道呢,兽医可能会在下个月得到一些虫族!
  • Woops @Josh,我尝试了您的插入语句,插入一个测量值需要 6 分钟:-P 我想我应该改用它来使用 executemany() !如果你有时间,your welcome to drop by Fake Programmers
【解决方案2】:

我认为您无法弄清楚如何将二维数据放入数据库。

如果您考虑 2 列之间的关系,您可以将其视为 2D 数据,其中第 1 列为 X 轴数据,第 2 列为 Y 轴数据。 3D 数据也是如此。

最后你的数据库应该是这样的:

Table: Dogs
    Columns: DogId, DogName -- contains data for each dog

Table: Measurements
    Columns: DogId, MeasurementId, 3D_DataId, 2D_DataId -- contains measurements of each dog

Table: 3D_data
    Columns: 3D_DataId, 3D_X, 3D_Y, 3D_Z -- contains all 3D data of a measurement

Table: 2D_data
    Columns: 2D_DataId, 2D_X, 2D_Y -- contains all 2D data of a measurement

此外,您可能希望按顺序存储 3D 数据和 2D 数据。在这种情况下,您必须添加一列来将该订单存储在 3D 数据和 2D 数据表中

【讨论】:

    【解决方案3】:

    我要添加到 Josh 的答案中的唯一一件事是,如果您不需要查询单个帧或传感器,只需将数组作为 BLOB 存储在 dog_measurement_data 表中。我以前用大量的二进制传感器数据集做过这个,效果很好。您基本上查询每个测量值的 2d 和 3d 数组,并在代码而不是数据库中操作它们。

    【讨论】:

    • 这应该作为对我的回答的评论发布,但是,我想你还不能发布 cmets :-) 作为回应,我想说这样做的缺点是,你需要一种可以可靠地从 BLOB 存储/检索的格式,例如 JSON 或其他一些序列化的 python 值。这可能不像听起来那么容易!
    【解决方案4】:

    Django 有一个库,用于将所有数据库工作封装到 Python 类中,因此在您必须做一些非常聪明的事情之前,您不必弄乱原始 SQL。尽管 Django 是 Web 应用程序的框架,你也可以use the database ORM by itself

    Josh 的模型在 Python 中使用 Django 如下所示:

    from django.db import models
    
    class Dog(models.Model):
        # Might want to look at storing birthday instead of age.
        # If you track age, you probably need another field telling
        # you when in the year age goes up by 1... and at that point,
        # you're really storing a birthday.
        name = models.CharField(max_length=64)
        age = models.IntegerField()
        genders = [
            ('M', 'Male'),
            ('F', 'Female'),
        ]
        gender = models.CharField(max_length=1, choices=genders)
    
    class Measurement(models.Model):
        dog = models.ForeignKey(Dog, related_name="measurements")
        paws = [
            ('FL', 'Front Left'),
            ('FR', 'Front Right'),
            ('RL', 'Rear Left'),
            ('RR', 'Rear Right'),
        ]
        paw = models.CharField(max_length=2, choices=paws)
        taken_at = models.DateTimeField(default=date, auto_now_add=True)
    
    class Measurement_Point(models.Model):
        measurement = models.ForeignKey(Measurement, related_name="data_points")
        frame = models.IntegerField()
        sensor_row = models.PositiveIntegerField()
        sensor_col = models.PositiveIntegerField()
        value = models.FloatField()
    
        class Meta:
            ordering = ['frame', 'sensor_row', 'sensor_col']
    

    id 字段是自动创建的。

    然后您可以执行以下操作:

    dog = Dog()
    dog.name = "Pochi"
    dog.age = 3
    dog.gender = 'M'
    # dog.gender will return 'M', and dog.get_gender_display() will return 'Male'
    dog.save()
    
    # Or, written another way:
    dog = Dog.objects.create(name="Fido", age=3, sex='M')
    

    进行测量:

    measurement = dog.measurements.create(paw='FL')
    for frame in range(248):
        for row in range(255):
            for col in range(63):
                measurement.data_points.create(frame=frame, sensor_row=row, 
                    sensor_col=col, value=myData[frame][row][col])
    

    最后,得到一个框架:

    # For the sake of argument, assuming the dogs have unique names.
    # If not, you'll need some more fields in the Dog model to disambiguate.
    dog = Dog.objects.get(name="Pochi", sex='M')
    # For example, grab the latest measurement...
    measurement = dog.measurements.all().order_by('-taken_at')[0]
    # `theFrameNumber` has to be set somewhere...
    theFrame = measurement.filter(frame=theFrameNumber).values_list('value')
    

    注意:这将返回一个元组列表(例如[(1.5,), (1.8,), ... ]),因为values_list() 可以一次检索多个字段。我不熟悉 NumPy,但我想它有一个类似于 Matlab 的 reshape 函数,用于将向量重新映射到矩阵。

    【讨论】:

      【解决方案5】:

      sqlalchemy package 让我受益匪浅;它是一个对象关系映射器。这意味着您可以在对象和数据之间创建一个非常清晰和明显的分离:

      SQL 数据库的行为不像对象 收藏的规模和规模越大 性能开始变得重要;目的 集合的行为不像表 和行越抽象开始 重要。 SQLAlchemy 旨在 兼顾这两个原则。

      您可以创建一个对象来代表您的不同名词(Dog、Measurement、Plate 等)。然后,您通过 sqlalchemy 构造创建一个表,该表将包含您想要关联的所有数据,例如 Dog 对象。最后在Dog 对象和dog_table 之间创建一个mapper

      这个没有例子很难理解,这里就不复述了。相反,请先阅读this case study,然后再学习this tutorial

      一旦您可以像在现实世界中那样思考DogsMeasurements(即对象本身),您就可以开始分解构成它们的数据。

      最后,尽量不要将您的数据与特定格式结合(就像您目前使用 numpy 数组所做的那样)。相反,您可以考虑简单的数字,然后根据需要将它们转换为您当前应用程序所需的特定格式(沿着模型-视图-控制器范式)。

      祝你好运!

      【讨论】:

        【解决方案6】:

        根据您的描述,我强烈建议您查看PyTables。它不是传统意义上的关系数据库,它具有您可能会使用的大部分功能(例如查询),同时允许轻松存储大型多维数据集及其属性。另外,它与 numpy 紧密集成。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-11-29
          • 2014-02-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-06-19
          相关资源
          最近更新 更多