2016-05-02 21 views
0

私は別の列に基づいてグループ内で注文する必要がある非常に大きなパンダのデータフレームを持っています。私はグループを反復する方法を知っています、グループの操作を行い、すべてのグループを1つのデータフレームに戻しますが、これは遅いですが、これを達成するより良い方法があるように感じます。ここに入力し、私がそれから欲しいものです。入力:グループ化されたデータフレームでの効率的な操作パンダ

ID price 
1 100.00 
1 80.00 
1 90.00 
2 40.00 
2 40.00 
2 50.00 

出力:

ID price order 
1 100.00 3 
1 80.00 1 
1 90.00 2 
2 40.00 1 
2 40.00 2 (could be 1, doesn't matter too much) 
2 50.00 3 

これは25万IDの効率、約5kkレコードを超えているので、重要です。

答えて

1

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

df["order"] = df.groupby("ID")["price"].rank(method="first") 
df 
Out[47]: 
    ID price order 
0 1 100.0 3.0 
1 1 80.0 1.0 
2 1 90.0 2.0 
3 2 40.0 1.0 
4 2 40.0 2.0 
5 2 50.0 3.0 

それは250000 IDの(i5-3330)と5メートルの行のデータセットの30代程度かかり:

df = pd.DataFrame({"price": np.random.rand(5000000), "ID": np.random.choice(np.arange(250000), size = 5000000)}) 
%time df["order"] = df.groupby("ID")["price"].rank(method="first") 
Wall time: 36.3 s 
+0

ありがとうございます!これは非常にうまく動作します –

+0

ようこそ。それが助けてくれてうれしい。 – ayhan

2

速度はあなたが望むものである場合には、 numpyでの複素数ソートを利用するため、少し複雑ですが、以下はかなり良いはずです。これは、パッケージnumpy-groupiesにaggregate-sortメソッドを記述するときに使用した手法(私の私)に似ています。

# get global sort order, for sorting by ID then price 
full_idx = np.argsort(df['ID'] + 1j*df['price']) 

# get min of full_idx for each ID (note that there are multiple ways of doing this) 
n_for_id = np.bincount(df['ID']) 
first_of_idx = np.cumsum(n_for_id)-n_for_id 

# subtract first_of_idx from full_idx 
rank = np.empty(len(df),dtype=int) 
rank[full_idx] = arange(len(df)) - first_of_idx[df['ID'][full_idx]] 
df['rank'] = rank+1 

は、それは時間がかかりすぎるので、私は実際に5メートルの行とパンダのバージョンを実行しなかったが(パンダからgroupby.rankを使用するよりもおよそ100倍高速である私のマシン上で5メートル行の2Sを取り、私は」どのように@ayhanが30代でそれをやったのかわからない、おそらくパンダのバージョンの違い?)。

これを使用する場合、私はそれを完全にテストすることをお勧めします。

+0

私のユースケースでは彼のソリューションが十分であるようですが、もしそうでなければ、これを調べます。ありがとう! –

+0

これは 'rank'よりもはるかに高速です。途中で同じ結果が得られます。 http://i.imgur.com/7UejPRI.png – ayhan

+0

このアプローチでは、idsはint> = 0であり、大きすぎないと仮定しています。これが当てはまらない場合は、追加の作業や少し異なるアプローチが必要です(ただし、一般的なアプローチはまだ有効です)。 –

関連する問題