0

日付を使用して辞書を反復処理する方法を教えてください。このようなデータセットがあります

data=[{u'a': u'D', u'b': 100.0, u'c': 201L, u'd': datetime.datetime(2007, 12, 29, 0, 0), u'e': datetime.datetime(2008, 1, 1, 6, 27, 41)},
      {u'a': u'W', u'b': 100.0, u'c': 201L, u'd': datetime.datetime(2007, 12, 29, 0, 0), u'e': datetime.datetime(2008, 2, 4, 6, 27, 41)},
      {u'a': u'W', u'b': 100.0, u'c': 202L, u'd': datetime.datetime(2007, 12, 30, 0, 0), u'e': datetime.datetime(2008, 1, 1, 4, 20, 44)},
      {u'a': u'D', u'b': 100.0, u'c': 202L, u'd': datetime.datetime(2007, 12, 30, 0, 0), u'e': datetime.datetime(2008, 3, 11, 6, 27, 41)},
      {u'a': u'D', u'b': 100.0, u'c': 202L, u'd': datetime.datetime(2007, 12, 30, 0, 0), u'e': datetime.datetime(2008, 5, 8, 11, 2, 41)},
      {u'a': u'D', u'b': 100.0, u'c': 203L, u'd': datetime.datetime(2008, 1, 2, 0, 0), u'e': datetime.datetime(2008, 6, 1, 6, 27, 41)},
      {u'a': u'W', u'b': 100.0, u'c': 204L, u'd': datetime.datetime(2008, 2, 9, 0, 0), u'e': datetime.datetime(2008, 4, 21, 12, 30, 51)},
      {u'a': u'D', u'b': 100.0, u'c': 204L, u'd': datetime.datetime(2008, 2, 9, 0, 0), u'e': datetime.datetime(2008, 8, 15, 15, 45, 10)}]

以下の形式の辞書に入れるにはどうすればよいですか

res={u'201L':(1,0,1),(2,1,0),(3,0,0),(4,0,0).. so on till (12,0,0),
u'202L':(1,1,0),(2,0,0),(3,0,1),(4,0,0),(5,0,1)...(12,0,0),
u'203L':(1,0,0),(2,0,0),(3,0,0),(4,0,0),(5,1,0)...(12,0,0),
u'204L':(1,0,0),(2,0,0),(3,0,0),(4,1,0),(5,0,0),(6,0,0,(7,0,0),(8,0,1)...(12,0,0)}

ここで、1、2、3 はカード発行日から 1 か月目、2 か月目などです。つまり、201L発行日はdatetime.datetime(2007, 12, 29, 0, 0)です202Ldatetime.datetime(2007, 12, 30, 0, 0)

最初の月は~までを意味2007-12-29します2008-1-29

  (1,0,1)---where 1 is the first month
  0 is no of times W
  1 is no of times D

私はこのようなことを試しました

data_dict=defaultdict(Counter)
date_dic={}
for x in data:
  a,b,c,d=x['a'],x['c'],x['d'],x['e']
  data_dict[b][a] += 1
for key , value in data_dict.items():
   date_dic[key] = tuple(map(datetime.date.isoformat, (c,d)))
   for value in range(1,30):
      if value not x: continue

上記の形式で取得するために何を追加できるかを if ループした後、行き詰まりました。出力としてこのようなものを取得することになります。

defaultdict(<class 'collections.Counter'>, {201L: Counter({u'D': 1, u'W': 1}), 202L: Counter({u'D': 2, u'W': 1}), 203L: Counter({u'D': 1}), 204L: Counter({u'D': 1, u'W': 1})})
4

1 に答える 1

2

日付のリストを作成し、そのリストから各アイテムを入れる「バケット」を見つけます。

datetime.timedelta()オブジェクトを使用して、開始点から相対的な新しい日付を作成できます。

startdate = data[0]['d']
buckets = [startdate + datetime.timedelta(days=30) * i for i in xrange(12)]

これで、他のすべてを比較する 12 の日付が得られたので、後続の各値をどのバケットに入れるかがわかります。

>>> buckets
[datetime.datetime(2007, 12, 29, 0, 0), datetime.datetime(2008, 1, 28, 0, 0), datetime.datetime(2008, 2, 27, 0, 0), datetime.datetime(2008, 3, 28, 0, 0), datetime.datetime(2008, 4, 27, 0, 0), datetime.datetime(2008, 5, 27, 0, 0), datetime.datetime(2008, 6, 26, 0, 0), datetime.datetime(2008, 7, 26, 0, 0), datetime.datetime(2008, 8, 25, 0, 0), datetime.datetime(2008, 9, 24, 0, 0), datetime.datetime(2008, 10, 24, 0, 0), datetime.datetime(2008, 11, 23, 0, 0)]

bisectモジュールを使用して、一致するバケットを見つけることができます。

from bisect import bisect

bisect(buckets, somedate) - 1  # Returns a value from 0 - 11

このようなバケットはユーザーごとに作成するため、別のマッピングでバケットを追跡する必要があります。現在のトランザクションの日付に合わせて、必要に応じて実際にバケットをその場で作成します。

次に、collections.defaultdictインスタンスを使用してキーごとの集計を追跡cします (入力を入力します)。

from collections import defaultdict

res = defaultdict(list)
empty_counts = {'D': 0, 'W': 0}

これにより、バケットが保持するリストと、入出金用の空のカウント ディクショナリが作成されます。ここで辞書を使用したのは、後で (不変の) タプルを操作するよりもはるかに簡単に使用できるためです。また、月番号 (1 ~ 12) も含めませんでした。意味がありません。各バケット (0 ~ 11) には既にインデックスがあり、可変数のバケットを持つことができます。

現在の日付に合わせて、必要に応じてバケットとカウンターを作成する必要があります。データをスキャンしてユーザーごとの最大トランザクション日を見つける代わりに、必要に応じてバケットとカウント リストを拡張します。

def expand_buckets(buckets, bucket_counts, start, transaction):
    # This function modifies the buckets and bucket_counts lists in-place
    if not buckets:
        # initialize the lists
        buckets.append(start)
        bucket_counts.append(dict(empty_counts))

    # keep adding 30-day spans until we can fit the transaction date
    while buckets[-1] + datetime.timedelta(days=30) < transaction:
        buckets.append(buckets[-1] + datetime.timedelta(days=30))
        bucket_counts.append(dict(empty_counts))

これでカウントを開始できます

per_user_buckets = defaultdict(list)

for entry in data:
    user = entry['c']
    type = entry['a']
    transaction_date = entry['e']
    buckets = per_user_buckets[user]
    bucket_counts = res[user]
    expand_buckets(buckets, bucket_counts, entry['d'], transaction_date)

    # count transaction date entries per bucket
    bucket = bisect(buckets, transaction_date) - 1
    bucket_counts[bucket][type] += 1

このbisect呼び出しにより、適切なバケットを簡単かつ迅速に選択できます。

入力例の結果は次のとおりです。

>>> pprint(dict(res))
{201L: [{'D': 1, 'W': 0},
        {'D': 0, 'W': 1}],
 202L: [{'D': 0, 'W': 1},
        {'D': 0, 'W': 0},
        {'D': 1, 'W': 0},
        {'D': 0, 'W': 0},
        {'D': 1, 'W': 0}],
 203L: [{'D': 0, 'W': 0},
        {'D': 0, 'W': 0},
        {'D': 0, 'W': 0},
        {'D': 0, 'W': 0},
        {'D': 0, 'W': 0},
        {'D': 1, 'W': 0}],
 204L: [{'D': 0, 'W': 0},
        {'D': 0, 'W': 0},
        {'D': 0, 'W': 1},
        {'D': 0, 'W': 0},
        {'D': 0, 'W': 0},
        {'D': 0, 'W': 0},
        {'D': 1, 'W': 0}]}
于 2013-04-24T14:24:45.367 に答える