2017-04-05 3 views
0

Seriesが与えられているので、シリーズに変更が発生する前に観測がいくつあるかを効率的に計算したいと思います。ここでは簡単な例です:シリーズの変更前の観測数を求める(pandas/numpy)

ser = pd.Series([1.2,1.2,1.2,1.2,2,2,2,4,3]) 

print(ser) 

0 1.2 
1 1.2 
2 1.2 
3 1.2 
4 2.0 
5 2.0 
6 2.0 
7 4.0 
8 3.0 

私はにつながることになるserに関数を適用したいと思います:

0 4 
1 3 
2 2 
3 1 
4 3 
5 2 
6 1 
7 1 
8 1 

私は大規模なシリーズで取り扱っておりますとおり、私にはない高速なソリューションを好むだろうループを伴う。

+1

何を試しましたか?また、ソリューションにループが含まれていない場合、入出力をスキャンして出力する方法はありますか? – shole

+1

問題を引き起こすコードを投稿してください。誰かのためにソリューションを設計するように求めるのは、私たちの目的を少し超えています。 – Prune

+0

私よりも速いコードを探しています。今度はコード – splinter

答えて

1

ここthis postに基づいてnumpyのアプローチだ -

def array_cumcount_descending(a): 
    idx = np.flatnonzero(a[1:] != a[:-1])+1 
    shift_arr = -np.ones(a.size,dtype=int) 

    if len(idx)>=1: 
     shift_arr[0] = idx[0] 
     shift_arr[idx[:-1]] = idx[1:] - idx[:-1] - 1 
     shift_arr[idx[-1]] = a.size - idx[-1] - 1  
    else: 
     shift_arr[0] = a.size 
    return shift_arr.cumsum() 

サンプルラン -

In [70]: ser 
Out[70]: 
0 1.2 
1 1.2 
2 1.2 
3 1.2 
4 2.0 
5 2.0 
6 2.0 
7 4.0 
8 3.0 
dtype: float64 

In [71]: array_cumcount_descending(ser.values) 
Out[71]: array([4, 3, 2, 1, 3, 2, 1, 1, 1]) 
1

あなたはcumcountgroupbyを使用することができます。

>>> ser.groupby(ser).cumcount(ascending=False)+1 
0 4 
1 3 
2 2 
3 1 
4 3 
5 2 
6 1 
7 1 
8 1 
dtype: int64 

DSMさんのコメント@を1として、あなたは同じ値の複数のブロックを持っているならば、上記の動作しませんが、あなたがしてソリューションを拡張することができます

>>> ser = pd.Series([1.2, 1.2, 1.2, 1.2, 2, 2, 2, 1.2, 1.2, 1.2, 4, 3]) 
>>> ser.groupby((ser != ser.shift()).cumsum()).cumcount(ascending=False)+1 
0  4 
1  3 
2  2 
3  1 
4  3 
5  2 
6  1 
7  3 
8  2 
9  1 
10 1 
11 1 
dtype: int64 
+1

IIUCの質問を更新します。これは、OPのシリーズの値が重複していない(不連続的には私が意味する)ことが起こるためにのみ機能するため、値のグループ化は変更のある場所のグループ化と同じです。 – DSM

+0

これは、ありがとうございます。より速いソリューションが存在する場合は、素晴らしいことができますが。 – splinter

+0

@splinterあなたのコードを見ることなく、スピードを比較することはできません。 – AChampion

関連する問題