2

次の質問はループで簡単に解決できますが、これを達成するためのより Pythonic な方法があるのではないかと思います。

本質的に、私はグループにクラスター化される傾向があるブーリアンの iterable を持っています。以下に例を示します。

[True, True, True, True, False, False, False, True, True, True, True, True]

s の各クラスターの開始インデックスと終了インデックスを選択したいと思いますTrue。ループを使用すると、これは簡単です。反復子が であるたびに、True既にTrueクラスターにいるかどうかを確認するだけで済みます。そうでない場合は、in_true_cluster変数を true に設定し、インデックスを保存します。を見つけたらFalse、index - 1 を終点として保存します。

これを行うためのよりpythonicな方法はありますか?私は PANDAS と NumPy も使用しているため、論理インデックスを使用したソリューションは受け入れられることに注意してください。

4

2 に答える 2

3

どうですか:

In [25]: l = [True, True, True, True, False, False, False, True, True, True, True, True]

In [26]: d = np.diff(np.array([False] + l + [False], dtype=np.int))

In [28]: zip(np.where(d == 1)[0], np.where(d == -1)[0] - 1)
Out[28]: [(0, 3), (7, 11)]

ここで、2 つの実行はインデックス[0; 3]および にあり[7; 11]ます。

于 2013-03-05T17:27:59.300 に答える
3

itertools実際には、これは numpy の方法です。これは、手動ループを使用するよりも高速である必要があります。

>>> a = np.array([True, True, True, True, False, False, False, True, True, True, True, True])
>>> np.diff(a)
array([False, False, False,  True, False, False,  True, False, False,
       False, False], dtype=bool)
>>> _.nonzero()
(array([3, 6]),)

コメントで述べたように、パンダgroupbyも機能します。


@poke を納得させるタイミング:

>>> %%timeit a = np.random.randint(2, size=1000000)
... np.diff(a).nonzero()
...
100 loops, best of 3: 12.2 ms per loop
>>> def cluster_changes(array):
...     changes = []
...     last = None
...     for i, elt in enumerate(array):
...         if elt != last:
...             last = elt
...             changes.append(i)
...     return changes
...
>>> %%timeit a = np.random.randint(2, size=1000000)
cluster_changes(a)
...
1 loops, best of 3: 348 ms per loop

これは、7 行の手動機能と比較して、ワンライナーを使用したこのアレイでは 30 倍です。(もちろん、ここのデータには OP のデータよりも多くのクラスター変更がありますが、それはそれほど大きな違いを補うものではありません。)

于 2013-03-05T17:23:58.123 に答える