2013-05-01 2 views
7

更新:バージョン0.20.0から、pandas cut/qcutは日付フィールドを処理します。詳細については、What's Newを参照してください。パンダの日付フィールドのcut/qcutに相当するものは何ですか?

pd.cutとpd.qcut今サポートdatetime64とtimedelta64 dtypes(GH14714、GH14798)

オリジナル質問:パンダカットとqcut機能がための連続したデータを 'バケット化' のための素晴らしいですピボットテーブルなどで使用していますが、ミックスで日時軸を取得する簡単な方法はわかりません。パンダはすべての時間関連のものでとても素晴らしいので、挫折!ここで

は簡単な例です:価格や数量のグループによってビンへ

def randomDates(size, start=134e7, end=137e7): 
    return np.array(np.random.randint(start, end, size), dtype='datetime64[s]') 

df = pd.DataFrame({'ship' : randomDates(10), 'recd' : randomDates(10), 
        'qty' : np.random.randint(0,10,10), 'price' : 100*np.random.random(10)}) 
df 

    price  qty recd    ship 
0 14.723510 3 2012-11-30 19:32:27 2013-03-08 23:10:12 
1 53.535143 2 2012-07-25 14:26:45 2012-10-01 11:06:39 
2 85.278743 7 2012-12-07 22:24:20 2013-02-26 10:23:20 
3 35.940935 8 2013-04-18 13:49:43 2013-03-29 21:19:26 
4 54.218896 8 2013-01-03 09:00:15 2012-08-08 12:50:41 
5 61.404931 9 2013-02-10 19:36:54 2013-02-23 13:14:42 
6 28.917693 1 2012-12-13 02:56:40 2012-09-08 21:14:45 
7 88.440408 8 2013-04-04 22:54:55 2012-07-31 18:11:35 
8 77.329931 7 2012-11-23 00:49:26 2012-12-09 19:27:40 
9 46.540859 5 2013-03-13 11:37:59 2013-03-17 20:09:09 

、私はそれらをバケットにカット/ qcutを使用することができます。

df.groupby([pd.cut(df['qty'], bins=[0,1,5,10]), pd.qcut(df['price'],q=3)]).count() 

         price qty recd ship 
qty  price    
(0, 1] [14.724, 46.541] 1 1 1 1 
(1, 5] [14.724, 46.541] 2 2 2 2 
     (46.541, 61.405] 1 1 1 1 
(5, 10] [14.724, 46.541] 1 1 1 1 
     (46.541, 61.405] 2 2 2 2 
     (61.405, 88.44] 3 3 3 3 

しかし、私はどんな簡単に見ることができません私の 'recd'または 'ship'日付フィールドで同じことをする方法。例えば、recdとshipの毎月のバケットで分けられた同様のカウントテーブルを生成します。 resample()にはすべての期間が入っている機械がありますが、ここではどのように適用するかわかりません。 'date cut'のバケット(またはレベル)はpandas.PeriodIndexと等しくなり、それからdf ['recd']の各値にその期間にラベルを付けるとします。

だから、私が探している出力の種類はのようになります。より一般的に

ship recv  count 
2011-01 2011-01 1 
     2011-02 3 
     ...  ... 
2011-02 2011-01 2 
     2011-02 6 
...  ...  ... 

を、私はミックスして出力で連続またはカテゴリ変数と一致することができるようにしたいと思います。そう、多分私は、ステータス、価格バケット、船とRECDバケットでカウントを集計する、DFはまた、赤/黄/緑の値を持つ「ステータス」列が含まれて想像:ボーナス質問として

ship recv  price status count 
2011-01 2011-01 [0-10) green  1 
          red  4 
       [10-20) yellow  2 
        ...  ... ... 
     2011-02 [0-10) yellow  3 
     ...  ...  ... ... 

、何ですgroupby()の結果を 'count'という単一の出力列だけに変更する最も簡単な方法は?

答えて

4

ここでは、pandas.PeriodIndexを使用する解決策があります(注意:PeriodIndexはでは '> 4M'などの倍数で時間ルールをサポートしていないようです)。私は あなたのボーナスの質問への答えは.size()だと思います。

In [49]: df.groupby([pd.PeriodIndex(df.recd, freq='Q'), 
    ....:    pd.PeriodIndex(df.ship, freq='Q'), 
    ....:    pd.cut(df['qty'], bins=[0,5,10]), 
    ....:    pd.qcut(df['price'],q=2), 
    ....:   ]).size() 
Out[49]: 
       qty  price 
2012Q2 2013Q1 (0, 5] [2, 5] 1 
2012Q3 2013Q1 (5, 10] [2, 5] 1 
2012Q4 2012Q3 (5, 10] [2, 5] 1 
     2013Q1 (0, 5] [2, 5] 1 
       (5, 10] [2, 5] 1 
2013Q1 2012Q3 (0, 5] (5, 8] 1 
     2013Q1 (5, 10] (5, 8] 2 
2013Q2 2012Q4 (0, 5] (5, 8] 1 
     2013Q2 (0, 5] [2, 5] 1 
4

はちょうどあなたがすることによってリサンプリングしたいフィールドのインデックスを設定する必要があり、ここではいくつかの例はどのようSeriesを使用して、あなたがそれに興味を持っているDataFrameの部品を置くことについての

In [36]: df.set_index('recd').resample('1M',how='sum') 
Out[36]: 
       price qty 
recd      
2012-07-31 64.151194 9 
2012-08-31 93.476665 7 
2012-09-30 94.193027 7 
2012-10-31   NaN NaN 
2012-11-30   NaN NaN 
2012-12-31 12.353405 6 
2013-01-31   NaN NaN 
2013-02-28 129.586697 7 
2013-03-31   NaN NaN 
2013-04-30   NaN NaN 
2013-05-31 211.979583 13 

In [37]: df.set_index('recd').resample('1M',how='count') 
Out[37]: 
2012-07-31 price 1 
      qty  1 
      ship  1 
2012-08-31 price 1 
      qty  1 
      ship  1 
2012-09-30 price 2 
      qty  2 
      ship  2 
2012-10-31 price 0 
      qty  0 
      ship  0 
2012-11-30 price 0 
      qty  0 
      ship  0 
2012-12-31 price 1 
      qty  1 
      ship  1 
2013-01-31 price 0 
      qty  0 
      ship  0 
2013-02-28 price 2 
      qty  2 
      ship  2 
2013-03-31 price 0 
      qty  0 
      ship  0 
2013-04-30 price 0 
      qty  0 
      ship  0 
2013-05-31 price 3 
      qty  3 
      ship  3 
dtype: int64 
+1

これは一般的な解決策のようではありません。 2つの異なる日付、または日付と非日付(カットまたはカテゴリ変数を使用)でグループ化する場合私は探している出力の構造で質問を更新します。 – patricksurry

0

です、シリーズオブジェクトにcutを呼び出しますか?

price_series = pd.Series(df.price.tolist(), index=df.recd) 

、その後

pd.qcut(price_series, q=3) 

のように。 (私は@ジェフの答えは最高だと思うが)

1

私はdatetime64 [ns]の基礎となる記憶形式に依存しているアイデアを思いついた。あなたはこの

def dcut(dts, freq='d', right=True): 
    hi = pd.Period(dts.max(), freq=freq) + 1 # get first period past end of data 
    periods = pd.PeriodIndex(start=dts.min(), end=hi, freq=freq) 
    # get a list of integer bin boundaries representing ns-since-epoch 
    # note the extra period gives us the extra right-hand bin boundary we need 
    bounds = np.array(periods.to_timestamp(how='start'), dtype='int') 
    # bin our time field as integers 
    cut = pd.cut(np.array(dts, dtype='int'), bins=bounds, right=right) 
    # relabel the bins using the periods, omitting the extra one at the end 
    cut.levels = periods[:-1].format() 
    return cut 

ようdcut()を定義する場合はその後、我々は、私が望んで行うことができます。

df.groupby([dcut(df.recd, freq='m', right=False),dcut(df.ship, freq='m', right=False)]).count() 

を取得するには:

   price qty recd ship 
2012-07 2012-10 1 1 1 1 
2012-11 2012-12 1 1 1 1 
     2013-03 1 1 1 1 
2012-12 2012-09 1 1 1 1 
     2013-02 1 1 1 1 
2013-01 2012-08 1 1 1 1 
2013-02 2013-02 1 1 1 1 
2013-03 2013-03 1 1 1 1 
2013-04 2012-07 1 1 1 1 
     2013-03 1 1 1 1 

私はあなたが同様に(dqcutを定義することができると思います)が最初に各日時の値を(指定した頻度で)その包含期間の開始を表す整数に「丸め」てから、qcut()を使用してそれらの境界を選択します。または、生の整数値のqcut()を最初に実行し、選択した頻度に基づいて結果のビンを丸めますか?

ボーナスの質問にまだ喜んでいませんか? :)

関連する問題