Как вставить массивы в базу данных? - PullRequest
17 голосов
/ 17 сентября 2010

В моем предыдущем вопросе многие пользователи хотели, чтобы я дал еще немного данных для игры. Итак, я начал экспортировать все свои данные и обрабатывать их с помощью Python, но потом понял: где мне оставить все эти данные?

Ну, я решил, что лучше всего было бы поместить их в базу данных, так что, по крайней мере, у меня нет для анализа необработанных файлов каждый раз. Но так как я ничего не знаю о базах данных, это оказывается довольно запутанным. Я попробовал несколько руководств, чтобы создать базу данных sqlite, добавить таблицу и поле и попытаться вставить мои numpy.arrays, но он не может заставить его работать.

Обычно мои результаты на собаку выглядят так: alt text

Итак, у меня 35 разных собак, и у каждой собаки 24 измерения. Каждое измерение имеет неизвестное количество контактов. Каждое измерение состоит из 3D-матрицы (248 кадров всей пластины [255x63]) и 2D-матрицы (максимальные значения для каждого датчика пластины [255x63]). Сохранение одного значения в базе данных не было проблемой, но, похоже, получение моих 2D-массивов там не сработало.

Итак, мой вопрос: как мне упорядочить это в базе данных и вставить в нее мои массивы?

Ответы [ 6 ]

9 голосов
/ 17 сентября 2010

Вы, вероятно, захотите начать с таблицы 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.

Затем вы захотите, чтобы таблицы хранили фактические кадры для каждого измерения, что-то вроде:

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?*)

Очевидно, замените measure_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`

И это даст вам все строки и столбцы для этого кадра.

7 голосов
/ 18 сентября 2010

Django имеет библиотеку для инкапсуляции всей работы с базой данных в классы Python, поэтому вам не придется возиться с необработанным SQL, пока вы не сделаете что-то действительно умное. Несмотря на то, что Django является фреймворком для веб-приложений, вы можете использовать базу данных ORM отдельно .

Модели Джоша выглядели бы так в 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, но думаю, что у него есть функция, аналогичная reshape функции Matlab для преобразования векторов в матрицы.

2 голосов
/ 17 сентября 2010

Единственное, что я хотел бы добавить к ответу Джоша, это то, что если вам не нужно запрашивать отдельные кадры или датчики, просто сохраните массивы как BLOB в таблице dog_measurement_data.Я делал это раньше с большим двоичным набором данных датчика, и это сработало хорошо.Вы в основном запрашиваете 2d и 3d массивы с каждым измерением и манипулируете ими в коде, а не в базе данных.

2 голосов
/ 17 сентября 2010

Я думаю, вы не можете понять, как поместить 2D-данные в базу данных.

Если вы думаете об отношении между 2 столбцами, вы можете думать о нем как о двухмерных данных, где 1-й столбец - данные оси X, а 2-й столбец - данные оси Y Аналогично для трехмерных данных.

Наконец, ваша БД должна выглядеть так:

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-данных

1 голос
/ 18 сентября 2010

Я получил много пользы от пакета sqlalchemy ;это объектно-реляционный картограф.Это означает, что вы можете создать очень четкое и четкое разделение между вашими объектами и вашими данными:

Базы данных SQL ведут себя не так, как коллекции объектов, тем больше размер и производительность начинают иметь значение;коллекции объектов ведут себя меньше, чем таблицы и строки, тем больше начинает иметь значение абстракция.SQLAlchemy стремится учитывать оба эти принципа.

Вы можете создавать объекты, представляющие различные существительные (собака, измерение, табличка и т. Д.).Затем вы создаете таблицу с помощью конструкций sqlalchemy, которая будет содержать все данные, которые вы хотите связать, скажем, с объектом Dog.Наконец, вы создаете mapper между объектом Dog и dog_table.

Это трудно понять без примера, и я не буду его здесь воспроизводить.Вместо этого, пожалуйста, начните с чтения этого учебного примера , а затем изучите этого учебного пособия .

Как только вы сможете думать о своих Dogs и Measurements, как вы это делаете вв реальном мире (то есть самих объектах) вы можете начать выделять данные, из которых они состоят.

Наконец, постарайтесь не объединять ваши данные в определенном формате (как вы это делаете в настоящее время, используя * 1027).* массивы).Вместо этого вы можете думать о простых числах и затем преобразовывать их по требованию в конкретный формат, который требует ваше текущее приложение (в соответствии с парадигмой Model-View-Controller).

Удачи!

0 голосов
/ 18 сентября 2010

Из вашего описания я очень рекомендую заглянуть в PyTables . Это не реляционная база данных в традиционном смысле, она имеет большинство функций, которые вы, вероятно, будете использовать (например, запросы), позволяя легко хранить большие многомерные наборы данных и их атрибуты. В качестве дополнительного бонуса, он тесно интегрирован с NumPy.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...