1

辞書で構成されたリストがあります。リストをサブセット化し、要素値の比較に基づいて辞書を選択したいと思います(この場合、日付ごとに1つの辞書のみを選択し、選択された辞書が最大realtime_start値を持つ辞書になります)。

リストの例は次のとおりです。

obs = [{'date': '2012-10-01',
  'realtime_end': '2013-02-18',
  'realtime_start': '2012-11-15',
  'value': '231.751'},
 {'date': '2012-10-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2012-12-19',
  'value': '231.623'},
 {'date': '2012-11-01',
  'realtime_end': '2013-02-18',
  'realtime_start': '2012-12-14',
  'value': '231.025'},
 {'date': '2012-11-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-01-19',
  'value': '231.071'},
 {'date': '2012-12-01',
  'realtime_end': '2013-02-18',
  'realtime_start': '2013-01-16',
  'value': '230.979'},
 {'date': '2012-12-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-02-19',
  'value': '231.137'},
 {'date': '2012-12-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-03-19',
  'value': '231.197'},
 {'date': '2013-01-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-02-21',
  'value': '231.198'},
 {'date': '2013-01-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-03-21',
  'value': '231.222'}]

realtime_startリストをサブセット化して、日付ごとに1つのdictのみが含まれ、最大値を持つdictが選択されるようにします。

この場合、リストがサブセット化されると、次のようになります。

sub = [ {'date': '2012-10-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2012-12-19',
  'value': '231.623'},
 {'date': '2012-11-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-01-19',
  'value': '231.071'},
 {'date': '2012-12-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-03-19',
  'value': '231.197'},
 {'date': '2013-01-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-03-21',
  'value': '231.222'}]

さらに、最大日付を指定したとします。

maxDate = "2013-02-21"

realtime_start値がmaxDateより大きくならないようにサブセット化するにはどうすればよいですか?この場合、次のサブセットが必要です。

sub2 = [ {'date': '2012-10-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2012-12-19',
  'value': '231.623'},
 {'date': '2012-11-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-01-19',
  'value': '231.071'},
 {'date': '2012-12-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-02-19',
  'value': '231.137'},
 {'date': '2013-01-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-02-21',
  'value': '231.198'} ]

Python 2.7.3でそのようなサブセット操作をどのように記述しますか?これはPythonで可能ですか?

ありがとう

4

2 に答える 2

4

あなたが使用することができますitertools.groupby

>>> import itertools
>>> # sort so that the same dates are contiguous
>>> obs.sort(key=lambda x: x['date'])
>>> grouped = itertools.groupby(obs, lambda x: x['date'])
>>> m = [max(g, key=lambda x: x['realtime_start']) for k, g in grouped]
>>> 
>>> import pprint
>>> pprint.pprint(m)
[{'date': '2012-10-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2012-12-19',
  'value': '231.623'},
 {'date': '2012-11-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-01-19',
  'value': '231.071'},
 {'date': '2012-12-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-03-19',
  'value': '231.197'},
 {'date': '2013-01-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-03-21',
  'value': '231.222'}]

他の条件も追加できます。

>>> grouped = itertools.groupby(obs, lambda x: x['date'])
>>> m = [max((w for w in g if w['realtime_start'] <= maxDate),
         key=lambda x: x['realtime_start']) for k, g in grouped]
>>> pprint.pprint(m)
[{'date': '2012-10-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2012-12-19',
  'value': '231.623'},
 {'date': '2012-11-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-01-19',
  'value': '231.071'},
 {'date': '2012-12-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-02-19',
  'value': '231.137'},
 {'date': '2013-01-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-02-21',
  'value': '231.198'}]

しかし、私のお気に入りのPythonデータ操作ライブラリであるパンダを確認することをお勧めします。表形式および時系列のデータに最適であり、それを使用したデータ操作は、自分で作成できるものよりもはるかに簡単です(機能的にはRに似ています)。 。

于 2013-03-02T23:51:58.403 に答える
1

基本的に、エントリをdateフィールドごとにグループ化してから、それらの各エントリに関連付けられたエントリのグループに対して操作を実行しますdate。私がこの種のことをする方法は、単純なol'を使用することですdict。そのような場合、私はadictを特別な種類のset「装飾されたセット」と考えます。そのすべての(必要に応じてハッシュ可能な)要素は、いくつかの(一般にハッシュ不可能な)ペイロードで「装飾」されます(つまり、関連する辞書の値)。この例では、この「装飾されたセット」の各要素は、のdateすべてのdictの中でフィールドに使用できる値の1つでobsあり、関連するペイロードは、obsそのキーをdateフィールドとして持つすべてのdictのリストです。

したがって、

In [4]: dobs = dict()
In [5]: for o in obs:
   ...:     d = o['date']
   ...:     if d not in dobs:
   ...:         dobs[d] = []
   ...:     dobs[d].append(o)
   ...: 

dict.setdefault次のように、ループの本体をforより簡潔に記述するために使用できます。

In [7]: for o in obs:
   ...:     dobs.setdefault(o['date'], []).append(o)
   ...: 

または、空のリストを辞書にプリロードしてから、キーがすでにdictにあるかどうかを確認せずにリストに追加することもできます。

In [9]: dobs = dict([(d, []) for d in set([e['date'] for e in obs])])
In [10]: for o in obs:
   ....:     dobs[o['date']].append(o)
   ....: 

dobs上記のいずれかを実行すると、キーがdate'sであり、値が対応するキーを値として持つすべてのdictのリストである辞書が作成されます。obsdate

これで、このdictを使用して町に行き、その値に任意の種類の関数を適用できます。たとえば、それぞれについてdate、最新のdictを抽出するには、次のrealtime_startようにします。

In [11]: rts = lambda x: x['realtime_start']
In [12]: [sorted(e, key=rts)[-1] for e in dobs.values() if e]
Out[12]: 
[{'date': '2013-01-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-03-21',
  'value': '231.222'},
 {'date': '2012-12-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-03-19',
  'value': '231.197'},
 {'date': '2012-10-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2012-12-19',
  'value': '231.623'},
 {'date': '2012-11-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-01-19',
  'value': '231.071'}]

if e上記の理解の最後にある修飾子はここでは必要ありませんが、「防御プログラミング」の名前に含めます。これがないと、の値のいずれかdobsが空になった場合、上記のコードは失敗します。これは当てはまりませんがdobs、より一般的な設定では問題になる可能性があります。これについては以下で詳しく説明します。)

realtime_startまた、で上限を設定しながら、上記の選択を実行する方法を尋ねます2013-02-21。この問題の場合、問題を2つのサブ問題に分割する方が概念的にクリーンであることがわかります。最初に、;dobsで指定された制約を満たすサブセットを生成します。realtime_start次に、制限されたdictで以前と同じ操作を実行します。したがって:

In [13]: dobs2 = dict([(k, [d for d in v if d['realtime_start'] <= maxDate])
   ....:               for k, v in dobs.items()])
In [14]: [sorted(e, key=rts)[-1] for e in dobs2.values() if e]
Out[14]: 
[{'date': '2013-01-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-02-21',
  'value': '231.198'},
 {'date': '2012-12-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-02-19',
  'value': '231.137'},
 {'date': '2012-10-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2012-12-19',
  'value': '231.623'},
 {'date': '2012-11-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-01-19',
  'value': '231.071'}]

繰り返しになりますif eが、この場合、修飾子は必要ありませんがmaxDate、一部のグループが空になるほど低い場合は、それが不可欠です。(これがないと、最初に検出された空のリストの最後の要素にアクセスしようとすると、IndexError例外が発生します。)

お気づきかもしれませんが、上記の結果の順序は実際の結果とは異なります。これは、組み込みのPythondictが順序を保持しないためです。obs元のリストの順序が重要な場合は、へのすべての呼び出しをへのdict呼び出しに置き換えることができますcollections.OrderedDict。例えば:

In [15]: from collections import OrderedDict
In [16]: dobs = OrderedDict()
In [17]: for o in obs:
   ....:     dobs.setdefault(o['date'], []).append(o)
   ....: 
In [18]: [sorted(e, key=rts)[-1] for e in dobs.values()]
Out[18]: 
[{'date': '2012-10-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2012-12-19',
  'value': '231.623'},
 {'date': '2012-11-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-01-19',
  'value': '231.071'},
 {'date': '2012-12-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-03-19',
  'value': '231.197'},
 {'date': '2013-01-01',
  'realtime_end': '9999-12-31',
  'realtime_start': '2013-03-21',
  'value': '231.222'}]
于 2013-03-03T02:16:05.850 に答える