2010-01-05 1 views
1

Я пытаюсь думать о том, как API Python может искать большие хранилища данных, такие как Cassandra. R, Matlab и NumPy имеют тенденцию использовать формулировку «все является матрицей» и выполнять каждую операцию отдельно. Эта модель доказала свою эффективность для данных, которые могут вписываться в память. Однако одним из преимуществ SAS для больших данных является то, что он выполняется по строкам, делая все вычисления строк перед переходом к следующему. Для такого хранилища данных, как Cassandra, эта модель кажется огромной победой - мы только циклически просматриваем данные один раз.Отложенное выполнение в python для больших данных

В Python подход SAS может выглядеть примерно так: (? Тоже)

with load('datastore') as data: 
    for row in rows(data): 
    row.logincome = row.log(income) 
    row.rich = "Rich" if row.income > 100000 else "Poor" 

Это явное, но имеет то преимущество, что только один раз зацикливание. Для меньших наборов данных производительность будет очень низкой по сравнению с NumPy, потому что функции не векторизуются с использованием скомпилированного кода. В R/Numpy мы имели бы гораздо более краткие и составили:

data.logincome = log(data.income) 
data.rich = ifelse(data.income > 100000, "Rich", Poor") 

Это будет выполнять очень быстро, потому что log и ifelse оба скомпилированные функции, что оператор на векторах. Однако недостатком является то, что мы будем дважды зацикливаться. Для небольших наборов данных это не имеет значения, но для поддерживаемого Cassandra хранилища данных я не вижу, как работает этот подход.

Вопрос: Есть ли способ сохранить второй API (например, R/Numpy/Matlab), но задержать вычисление. Возможно, вызывая функцию синхронизации (данных) в конце?

Альтернативные идеи? Было бы неплохо поддерживать синтаксис типа NumPy, поскольку пользователи будут использовать NumPy для небольших операций и будут иметь интуитивное понимание того, как это работает.

ответ

2

Я ничего не знаю о Cassandra/NumPy, но если вы адаптируете свой второй подход (используя NumPy) для обработки данных в кусках разумного размера, вы можете извлечь выгоду из кэша CPU и/или файловой системы и, следовательно, предотвратить любое замедление, вызванное циклическим переходом по данным дважды, не отказываясь от использования оптимизированных функций обработки.

1

У меня нет идеального ответа, просто грубая идея, но, возможно, это стоит того. Он сосредотачивается вокруг генераторов Python, как комбинация между производителем и потребителем.

С одной стороны, вы не хотите, чтобы петли дважды, я думаю, что нет никакого пути вокруг явного цикла для строк, например:

for row in rows(data): 
    # do stuff with row 

Теперь, кормить строку в (произвольное количество) потребителей, которые - не дросселируют - генераторы снова. Но вы бы использовали способ генератора send. В качестве примера для такого потребителя, вот эскиз riches:

def riches(): 
    rich_data = [] 
    while True: 
     row = (yield) 
     if row == None: break 
     rich_data.append("Rich" if row.income > 100000 else "Poor") 
    yield rich_data 

Первый выход (выражение) просто в качестве топлива для отдельных строк в riches. Он делает свою работу, создавая массив результатов. После цикла while второй выход (оператор) используется для фактического предоставления результирующих данных вызывающему.

Возвращаясь к петле вызывающего абонента, это может выглядеть коснуться так:

richConsumer = riches() 
richConsumer.next() # advance to first yield 
for row in rows(data): 
    richConsumer.send(row) 
    # other consumers.send(row) here 
richConsumer.send(None) # make consumer exit its inner loop 
data.rich = richConsumer.next() # collect result data 

Я не проверял этот код, но это, как я думаю об этом. Он не имеет симпатичного компактного синтаксиса векторных функций. Но он делает основной цикл очень простым и инкапсулирует всю обработку в отдельных потребителях.Дополнительные потребители могут быть хорошо уложены друг на друга. И API можно было бы дополнительно отполировать, нажав на управляющий код генератора, например, границ объекта. HTH

+0

Я не уверен, что полностью слежу за тем, что вы пытаетесь сделать. Как это улучшается по сравнению с моей первой опцией, которая просто перебирает строки, где строки представляют собой представление на базовые данные? – Tristan

+0

Ну, для одного это подтверждает необходимость петли верхнего уровня. С другой стороны, я подумал, что одна из ваших проблем заключалась в том, чтобы обработать код из тела цикла и в отдельных функциях (вы говорили о преимуществе «скомпилированных функций», хотя я не уверен, насколько это имеет смысл в Python, но это имеет большой смысл, если вы подумываете о том, чтобы вывести эти функции на C-код позже). Третьей задачей был аккуратный API для функций обработки. Учитывая эти ограничения, я думал, что этот подход производителей-потребителей является хорошим компромиссом. Но YMMV. – ThomasH

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