1

Python API が Cassandra のような大規模なデータストアをどのように検索するかを考えようとしています。R、Matlab、および NumPy は、「すべてが行列である」定式化を使用し、各操作を個別に実行する傾向があります。このモデルは、メモリに収まるデータに対して効果的であることが証明されています。ただし、ビッグ データに対する SAS の利点の 1 つは、行ごとに実行し、すべての行の計算を行ってから次の行に移動することです。Cassandra のようなデータストアの場合、このモデルは大きなメリットのように思えます。データを 1 回ループするだけです。

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"

これは (あまりにも?) 明示的ですが、ループが 1 回だけであるという利点があります。小さいデータセットの場合、コンパイルされたコードを使用して関数がベクトル化されないため、NumPy に比べてパフォーマンスが非常に悪くなります。R/Numpy では、はるかに簡潔でコンパイルされたものになります。

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

logifelseはどちらもベクトルを操作するコンパイル済み関数であるため、これは非常に高速に実行されます。ただし、欠点は、2 回ループすることです。小さなデータセットの場合、これは問題ではありませんが、Cassandra でサポートされているデータストアの場合、このアプローチがどのように機能するかわかりません。

質問: 2 番目の API (R/Numpy/Matlab など) を保持し、計算を遅らせる方法はありますか? おそらく、最後に sync(data) 関数を呼び出すことでしょうか?

別のアイデア?ユーザーは小さな操作に NumPy を使用し、それがどのように機能するかを直感的に把握できるため、NumPy 型の構文を維持するとよいでしょう。

4

2 に答える 2

2

Cassandra/NumPy については何も知りませんが、(NumPy を使用して) 2 番目のアプローチを適応させて妥当なサイズのチャンクでデータを処理すると、CPU および/またはファイルシステム キャッシュの恩恵を受ける可能性があり、したがって、最適化された処理関数を使用する利点をあきらめずに、データを 2 回ループします。

于 2010-01-05T23:42:47.213 に答える
1

私には完璧な答えはありません。大まかな考えですが、おそらくそれは価値があります。これは、Pythonジェネレーターを中心に、プロデューサーとコンシューマーのスタイルの組み合わせのようなものです。

1つは、2回ループしたくないので、次のように行の明示的なループを回避する方法はないと思います。

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

最初のyield(式)は、個々の行に燃料を供給することrichesです。それはそのことを行い、ここで結果配列を構築します。whileループの後、2番目のyield(ステートメント)を使用して、結果データを呼び出し元に実際に提供します。

発信者ループに戻ると、次のようになります。

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

于 2010-01-07T22:19:15.737 に答える