如何将数组插入数据库?

时间:2010-09-17 19:16:32

标签: python database-design numpy

In my previous question许多用户希望我为玩具提供更多数据。所以我开始导出所有数据并用Python处理它,但后来我意识到:我在哪里留下所有这些数据?

我确定最好将它们放在数据库中,所以至少我每次都没有to parse the raw files。但由于我对数据库一无所知,因此结果令人困惑。我尝试了一些教程来创建一个sqlite数据库,添加一个表和字段并尝试插入我的numpy.arrays,但它无法让它工作。

通常我的每只狗的结果如下所示: alt text

所以我有35只不同的狗,每只狗有24只。每个测量本身都有未知数量的联系人。每个测量由3D阵列(整个板的248帧[255x63])和2D阵列(板的每个传感器的最大值[255x63])组成。在数据库中存储一个值不是问题,但在那里获取我的2D数组似乎不起作用。

所以我的问题是如何在数据库中订购并将数组插入其中?

6 个答案:

答案 0 :(得分:9)

你可能想要从一个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()); * {em>? *是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`

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

答案 1 :(得分:7)

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

Josh的模型在使用Django的Python中看起来像这样:

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函数的函数,用于将向量重映射到矩阵。

答案 2 :(得分:2)

我认为你无法弄清楚如何将2D数据放入数据库。

如果考虑2列之间的关系,可以将其视为2D数据,第1列为X轴数据,第2列为Y轴数据。同样适用于3D数据。

最后你的db应该是这样的:

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 :(得分:2)

我唯一要补充的是Josh的答案是,如果您不需要查询单个帧或传感器,只需将数组存储为dog_measurement_data表中的BLOB。之前我已经使用大量的二进制传感器数据集完成了这项工作并且运行良好。您基本上每次测量都会查询2d和3d数组,并在代码而不是数据库中对它们进行操作。

答案 4 :(得分:1)

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

  

SQL数据库的行为不像对象   收藏品越多,尺寸越大   表现开始重要;宾语   集合表现得不像表格   和行越抽象开始   很重要。 SQLAlchemy的目标是   适应这两个原则。

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

如果没有示例,这很难理解,我不会在这里重现一个。相反,请先阅读this case study,然后研究this tutorial

一旦你能够像在现实世界中那样想到你的DogsMeasurements(也就是对象本身),你就可以开始将构成它们的数据分解出来。

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

祝你好运!

答案 5 :(得分:0)

根据您的说明,我强烈建议您查看PyTables。它不是传统意义上的关系数据库,它具有您可能正在使用的大多数功能(例如查询),同时允许轻松存储大型,多维数据集及其属性。作为额外的奖励,它与numpy紧密结合。