2014-09-13 4 views
0

Следующий запрос вытаскивает ca. 100'000 datapoints в python. Данные будут отображаться с помощью matplotlib.denormalized numpy массивы из postgres

cur.execute("""SELECT \ 
     loggingdb_ips_integer.ipsvalue, 
     loggingdb_ips_integer.ipstimestamp, 
     loggingdb_ips_integer.varid 
     FROM public.loggingdb_ips_integer 
     WHERE 
     (loggingdb_ips_integer.varid = 17884) OR 
     (loggingdb_ips_integer.varid = 55437) OR 
     (loggingdb_ips_integer.varid = 34637) OR 
     (loggingdb_ips_integer.varid = 17333) 
     ; """) 

Является ли это более эффективно работать 4 запросов с каждым ИНЕКЕМ по отдельности, или я должен скорее тянуть в целом энчиладу сразу, и превратить его в Numpy массива с 3 осями? И если последний более эффективен, каков наилучший способ преобразования (нормализации?) Массива? Пожалуйста, не прыгай на меня из-за моей наивности - я - врач по образованию; мое понимание кодирования ОЧЕНЬ ограничено!

+0

У вас есть две колонки и 4 возможных варианта. Какими будут 3 оси? – unutbu

+0

Они будут ips_value, ipstimestamp и varid. Я исправлю запрос соответствующим образом. – aag

+0

удалил флаг matplotlib as, в то время как эти данные предназначены для построения графика, этот вопрос не связан с указанным графиком. – tacaswell

ответ

1

Связь между Python и базой данных относительно медленная. Поэтому обычно вы хотите уменьшить количество запросов. Сделайте так же, как и всю базу данных, в базе данных, и вытащите только те данные, которые вам нужны.

Эти общие правила большого пальца приводят меня к предположению, что использование 1 запроса будет лучше, чем 4 запроса. Однако, 100K строк не очень много, поэтому не имеет значения, какой метод вы используете. Если вы не собираетесь запускать этот код миллионы раз и вам нужно сбрить каждую наносекунду, вы можете потратить больше времени на то, чтобы беспокоиться об этом, а не о том, чтобы сохранить время, просто выбрав его. И если вам действительно нужна такая производительность, тогда вы должны переосмыслить, является ли Python правильным языком для этой работы. Как говорится, preoptimization is the root of all evil.

Но поскольку это, скорее всего, не будет основным узким местом вашего кода, я бы выбрал, какой метод использовать на основе того, какой код проще всего читать и поддерживать, не обязательно на котором быстрее.

Если есть точно одинаковое количество строк для каждого varid то вы можете использовать перепрофилирование трик NumPy задобрить данные в 3 осей, причем первая ось, соответствующая varids (см ниже). В этом случае выполнение одного запроса может быть самым простым и быстрым.

Если количество строк не совсем одинаково, код становится немного сложнее. Для выбора правильных строк вам понадобится цикл Python и логическая маска NumPy. В этом случае было бы проще просто сделать четыре отдельных запроса.


Теперь, из любопытства я решил проверить мое утверждение, что один запрос быстрее, чем 4. Может быть, вы найдете здесь код вы можете повторно использовать.

import oursql 
import config 
import numpy as np 

def create_random_data(): 
    connection = oursql.connect(
     host=config.HOST, user=config.USER, passwd=config.PASS, 
     db='test') 
    with connection.cursor() as cursor: 
     sql = 'DROP TABLE IF EXISTS `mytable`' 
     cursor.execute(sql) 
     sql = '''CREATE TABLE `mytable` (
      `id` INT(11) NOT NULL AUTO_INCREMENT, 
      `ipsvalue` INT(11) DEFAULT NULL, 
      `ipstimestamp` INT(11) DEFAULT NULL, 
      `varid` INT(11) DEFAULT NULL,   
      PRIMARY KEY (`id`) 
      ) ENGINE=MyISAM DEFAULT CHARSET=latin1''' 
     cursor.execute(sql) 
     sql = ''' 
      INSERT INTO mytable (ipsvalue, ipstimestamp, varid) 
      VALUES (?, ?, ?)''' 
     N = 10**5 
     args = np.empty((N, 3)) 
     args[:, :-1] = np.random.randint(100, size=(N, 2)) 
     args[:, -1] = np.tile(np.array([17884, 55437, 34637, 17333]), N//4) 
     cursor.executemany(sql, args) 

def one_query(): 
    connection = oursql.connect(
     host=config.HOST, user=config.USER, passwd=config.PASS, 
     db='test') 
    with connection.cursor() as cursor: 
     varids = sorted((17884, 55437, 34637, 17333)) 
     sql = '''SELECT varid, ipsvalue, ipstimestamp FROM mytable 
       WHERE varid IN {} 
       ORDER BY varid, ipstimestamp, ipsvalue'''.format(tuple(varids)) 
     cursor.execute(sql) 
     data = np.array(cursor.fetchall()) 
     data = data.reshape(4, -1, 3) 
     arr = dict() 
     for i, varid in enumerate(varids): 
      arr[varid] = data[i] 
     return arr 

def four_queries(): 
    connection = oursql.connect(
     host=config.HOST, user=config.USER, passwd=config.PASS, 
     db='test') 
    with connection.cursor() as cursor: 
     arr = dict() 
     varids = (17884, 55437, 34637, 17333) 
     for varid in varids: 
      sql = '''SELECT varid, ipsvalue, ipstimestamp FROM mytable 
        WHERE varid = ? 
        ORDER BY ipstimestamp, ipsvalue''' 
      cursor.execute(sql, [varid]) 
      arr[varid] = np.array(cursor.fetchall()) 
     return arr 

arr = one_query() 
arr2 = four_queries() 
assert all([np.all(arr[key]==arr2[key]) for key in arr]) 

Оба one_query и four_queries возвращает Dict, ключи которого varid значения. Как вы можете видеть, производительность не отличается, хотя с помощью одного запроса несколько быстрее, чем четыре:

In [219]: %timeit four_queries() 
1 loops, best of 3: 238 ms per loop 

In [221]: %timeit one_query() 
1 loops, best of 3: 195 ms per loop 
1

Запрос будет, безусловно, будет быстрее, чтобы запустить его только один раз.Что касается «нормализацией» данные (я думаю, что вы имеете в виду http://en.wikipedia.org/wiki/Feature_scaling)

Scikit имеет функцию scale, которая хорошо работает с NumPy (но вы должны сгруппировать его самостоятельно)

Вы также можете сделать это в PostgreSQL с:

select 
    col 
    ,avg(col) 
    ,stddev(col) 
    from thetable 
    group by col 

, а затем использовать Z-счет формулу для масштабирования индивидуума путем присоединения к таблице:

select 
    (col - avg)/stddev as zscore 
from thetable as t 
    join ( 
    paste the query above here 
    ) as aggr on aggr.col=t.col 

- где col будет varid. Возможно, это не так важно для производительности, когда вы это делаете. Его звук больше похож на вашу проблему, так как группировать и масштабировать данные и что будет проще для вас.

Смежные вопросы