1

itertools.groupby によって生成された集計を処理 (合計、カウント) する組み込みの (または単純な) 方法はありますか?

たとえば、10% の割引があるコード例のテーブルを考えると...

したい:

# Select each city...
for city,city_purchases_d in itertools.groupby(transaction_l, 
                                               lambda d: d["city"]):
  print Aggregate( city,sum(|qty|),sum(|qty * price|)*(1-discount) ) *
              city_purchases_d

入力データ:

discount=0.10 # 10%

transaction_l=(
  dict(trans=201, name="Anne",  city="LAX", item="Apple", qty=10, price=1.33),
  dict(trans=202, name="Betty", city="LAX", item="Banana",qty=20, price=2.33),
  dict(trans=203, name="Carol", city="LAX", item="Cherry",qty=30, price=3.33),
  dict(trans=101, name="Andy",  city="NYC", item="Avodado",qty=1, price=1.32),
  dict(trans=102, name="Andy",  city="NYC", item=u"Açaí",  qty=1, price=1.70),
  dict(trans=103, name="Bob",   city="NYC", item="Bacuri", qty=3, price=2.10),
  dict(trans=104, name="Cliff", city="NYC", item="Carrot", qty=4, price=2.22),
  dict(trans=105, name="David", city="NYC", item="Donut",  qty=5, price=3.00)
)

出力は次のようになります。

('LAX',60,143.82)
('NYC',14,29.88)

すなわち

In LAX purchased 60 fruit at the total price of $143.82   
In NYC purchased 14 fruit at the total price of $29.88

ps。これに似た質問がたくさんあることに気付きました...しかし、単純に(のような)city,sum(|qty|),sum(|qty * price|)*(1-discount)集計のための単純な式を取るものはありません。

編集:(ジェネレータ内包表記を使用することを犠牲にして)次のように効果をほぼ達成できます:

discount=0.10 # 10%
desc_f="In %s purchased %s fruit at the total price of $%.2f"
for city,city_purchases_d in itertools.groupby(transaction_l, lambda d: d["city"]):
# alternatively - Plan B: manually creating aggregation DOES also work:
  qty_x_price=list(trans["qty"]*trans["price"] for trans in list(city_purchases_d))
  qty=(trans["qty"] for trans in city_purchases_d)
  print desc_f%(city,sum(qty),sum(qty_x_price)*(1-discount))
4

3 に答える 3

1

おそらくユーザーによる入力など、データの集計処理にある程度の柔軟性が必要だと思いますか? それ以外の場合、これを行うのは非常に簡単ですitertools.groupby:

from itertools import groupby

discount=0.10
transaction_l=(
  dict(trans=201, name="Anne",  city="LAX", item="Apple", qty=10, price=1.33),
  dict(trans=202, name="Betty", city="LAX", item="Banana",qty=20, price=2.33),
  dict(trans=203, name="Carol", city="LAX", item="Cherry",qty=30, price=3.33),
  dict(trans=101, name="Andy",  city="NYC", item="Avodado",qty=1, price=1.32),
  dict(trans=102, name="Andy",  city="NYC", item=u"Açaí",  qty=1, price=1.70),
  dict(trans=103, name="Bob",   city="NYC", item="Bacuri", qty=3, price=2.10),
  dict(trans=104, name="Cliff", city="NYC", item="Carrot", qty=4, price=2.22),
  dict(trans=105, name="David", city="NYC", item="Donut",  qty=5, price=3.00)
)
desc_f = 'In %s purchased %s fruit at the total price of $%.2f'

for city, transactions in groupby(transaction_l, key=lambda d: d['city']):
    transactions = list(transactions)
    print desc_f % (city,
                    sum(t['qty'] for t in transactions),
                    sum( (t['qty']*t['price'])*(1-discount)
                        for t in transactions))

出力

LAX で合計 143.82 ドルで 60 個の果物を購入しました
NYCで合計29.88ドルで14個の果物を購入

データに対して任意の「クエリ」を実行する柔軟性が必要な場合、これは素朴な (または奇妙な) 提案かもしれませんが、インメモリ SQLite データベースに対して SQL クエリを使用しますか?

import sqlite3

discount=0.10 # 10%

transaction_l=(
  dict(trans=201, name="Anne",  city="LAX", item="Apple", qty=10, price=1.33),
  dict(trans=202, name="Betty", city="LAX", item="Banana",qty=20, price=2.33),
  dict(trans=203, name="Carol", city="LAX", item="Cherry",qty=30, price=3.33),
  dict(trans=101, name="Andy",  city="NYC", item="Avodado",qty=1, price=1.32),
  dict(trans=102, name="Andy",  city="NYC", item=u"Açaí",  qty=1, price=1.70),
  dict(trans=103, name="Bob",   city="NYC", item="Bacuri", qty=3, price=2.10),
  dict(trans=104, name="Cliff", city="NYC", item="Carrot", qty=4, price=2.22),
  dict(trans=105, name="David", city="NYC", item="Donut",  qty=5, price=3.00)
)

memdb = sqlite3.connect(':memory:')
cursor = memdb.cursor()
# create an in-memory table
r = cursor.execute('create table transactions (trans int, name varchar(30), city char(3), item varchar(20), qty int, price numeric)')
result = cursor.executemany('insert into transactions (trans, name, city, item, qty, price) values (:trans, :name, :city, :item, :qty, :price)', transaction_l)
assert result.rowcount == len(transaction_l)

result = cursor.execute('select city, sum(qty), sum(qty*price)*(1-{}) from transactions group by city'.format(discount))

desc_f = 'In {} purchased {} fruit at the total price of ${:.2f}'
for row in result:
    print desc_f.format(*row)

memdb.close()

出力

LAX で合計 143.82 ドルで 60 個の果物を購入しました
NYCで合計29.88ドルで14個の果物を購入

したがって、次のような SQL クエリを作成する必要があります。

select city, sum(qty), sum(qty*price)*(1-0.1) from transactions group by city

これから:

city,sum(|qty|),sum(|qty * price|)*(1-discount)

これはかなり実行可能です。

于 2015-03-15T12:34:02.143 に答える
0

Pandas モジュールを使用すると、より簡単な方法で目的の結果をアーカイブできます。

import pandas as pd

discount = 0.2

df = pd.DataFrame(list(transaction_l))
df['total_price'] = df.qty*df.price*(1-discount)
res = df.groupby('city').sum()[['qty', 'total_price']]
print(res)
#       qty  total_price
#city 
#LAX    60       127.84
#NYC    14        26.56
于 2015-03-15T12:34:29.253 に答える