2016-05-27 29 views
12

私はパンダrollingの機能を使用して回転多因子回帰を実行するよう動機づけられました(この多項式回帰多因子回帰についてはNOTです)。私は、df.rolling(2)の後にapplyを使用し、結果としてpd.DataFrameを取って、.valuesでndarrayを抽出し、必要な行列乗算を実行することを期待しました。そんなことはできませんでした。ここで なぜパンダローリングは1次元のndarrayを使用するのですか

は、私が見つけたものです:

print "\ndf = \n", df 
print "\nX = \n", X 
print "\ndf.shape =", df.shape, ", X.shape =", X.shape 

df = 
     A  B 
0 0.44 0.41 
1 0.46 0.47 
2 0.46 0.02 
3 0.85 0.82 
4 0.78 0.76 

X = 
[[ 0.93] 
[ 0.83]] 

df.shape = (5, 2) , X.shape = (2L, 1L) 

行列の乗算が正常に動作します:

df.values.dot(X) 

array([[ 0.7495], 
     [ 0.8179], 
     [ 0.4444], 
     [ 1.4711], 
     [ 1.3562]]) 

行ドットで行を実行するために適用する使用のような物体が見える何

import pandas as pd 
import numpy as np 

np.random.seed([3,1415]) 
df = pd.DataFrame(np.random.rand(5, 2).round(2), columns=['A', 'B']) 
X = np.random.rand(2, 1).round(2) 

製品は期待どおりに動作します。

df.apply(lambda x: x.values.dot(X)[0], axis=1) 

0 0.7495 
1 0.8179 
2 0.4444 
3 1.4711 
4 1.3562 
dtype: float64 

GROUPBY - >私が期待するように動作し適用します。

df.groupby(level=0).apply(lambda x: x.values.dot(X)[0, 0]) 

0 0.7495 
1 0.8179 
2 0.4444 
3 1.4711 
4 1.3562 
dtype: float64 

をしかし、私は実行すると:

df.rolling(1).apply(lambda x: x.values.dot(X)) 

私が手:

AttributeError: 'numpy.ndarray' object has no attribute 'values'

オクラホマので、パンダれますそのrollingの実装内にストレートndarrayを使用します。私はそれを処理することができます。代わりにndarrayを取得するために.valuesを使用しての、試してみましょう:

df.rolling(1).apply(lambda x: x.dot(X)) 

shapes (1,) and (2,1) not aligned: 1 (dim 0) != 2 (dim 0)

待って!何?!

私はローリングが何をしているかを見るカスタム関数を作成しました。

def print_type_sum(x): 
    print type(x), x.shape 
    return x.sum() 

はその後走っ:

print df.rolling(1).apply(print_type_sum) 

<type 'numpy.ndarray'> (1L,) 
<type 'numpy.ndarray'> (1L,) 
<type 'numpy.ndarray'> (1L,) 
<type 'numpy.ndarray'> (1L,) 
<type 'numpy.ndarray'> (1L,) 
<type 'numpy.ndarray'> (1L,) 
<type 'numpy.ndarray'> (1L,) 
<type 'numpy.ndarray'> (1L,) 
<type 'numpy.ndarray'> (1L,) 
<type 'numpy.ndarray'> (1L,) 
     A  B 
0 0.44 0.41 
1 0.46 0.47 
2 0.46 0.02 
3 0.85 0.82 
4 0.78 0.76 

を私はpd.DataFrameを結果としてそれは良いことだ、と同じです。しかし、それは10個の一次元のndarrayオブジェクトを印刷しました。何rolling(2)について

print df.rolling(2).apply(print_type_sum) 

<type 'numpy.ndarray'> (2L,) 
<type 'numpy.ndarray'> (2L,) 
<type 'numpy.ndarray'> (2L,) 
<type 'numpy.ndarray'> (2L,) 
<type 'numpy.ndarray'> (2L,) 
<type 'numpy.ndarray'> (2L,) 
<type 'numpy.ndarray'> (2L,) 
<type 'numpy.ndarray'> (2L,) 
     A  B 
0 NaN NaN 
1 0.90 0.88 
2 0.92 0.49 
3 1.31 0.84 
4 1.63 1.58 

同じこと、出力を期待するが、それは8つのndarrayオブジェクトを印刷。 rollingは、ndarrayの形状のndarrayであると予想されたものとは対照的に、各列に対して長さがwindowの単一のndarrayを生成している。(window, len(df.columns))

質問はなぜですか?

私は現在、ローリングマルチファクタ回帰を簡単に実行する方法がありません。

+1

これは、[既知の問題](ですhttp:// stackoverflow.com/a/21026837/5276797)。私は最近、ジェフに尋ねました。コメントで彼の答えを読むことができます! – IanS

+0

パンダ0.20の最先端のソリューションとは何ですか?多くの改良が施されたようです。 OPの目的はrolling()。apply()を使って達成可能か? – Zhang18

答えて

4

In [101]: df = pd.DataFrame(np.random.rand(5, 2).round(2), columns=['A', 'B']) 

In [102]: X = np.array([2, 3]) 

In [103]: rolled_df = roll(df, 2) 

In [104]: %timeit rolled_df.apply(lambda df: pd.Series(df.values.dot(X))) 
100 loops, best of 3: 5.51 ms per loop 

In [105]: %timeit get_sliding_window(df, 2).dot(X) 
10000 loops, best of 3: 43.7 µs per loop 

は、結果を確認してください - 私はそこ

In [106]: rolled_df.apply(lambda df: pd.Series(df.values.dot(X))) 
Out[106]: 
     0  1 
1 2.70 4.09 
2 4.09 2.52 
3 2.52 1.78 
4 1.78 3.50 

In [107]: get_sliding_window(df, 2).dot(X) 
Out[107]: 
array([[ 2.7 , 4.09], 
     [ 4.09, 2.52], 
     [ 2.52, 1.78], 
     [ 1.78, 3.5 ]]) 

巨大な改善を、より大きい配列で目立つことを望むでしょう!私はpd.DataFrame.rolling(に行われるように全体のローリング・ウィンドウを返すために必要なので、上記の回答に次の変更を加え

+0

get_sliding_windowを使用しようとすると、未解決の参照エラーが発生します – RaduS

+0

@ RADADSエラーはどういう意味ですか? – Divakar

6

この問題を回避するために私が行ったことを共有したいと考えました。

pd.DataFrameとウィンドウが与えられた場合、私はnp.dstacksee answer)を使用してスタックndarrayを生成します。その後、pd.Panelに変換し、pd.Panel.to_frameを使用してpd.DataFrameに変換します。現時点では、元のpd.DataFrameを基準にしてインデックスに追加のレベルを持つpd.DataFrameがあり、新しいレベルには各ローリング期間に関する情報が含まれています。たとえば、ロールウィンドウが3の場合、新しいインデックスレベルは[0, 1, 2]になります。各期間のアイテム。私は今groupbylevel=0になり、groupbyオブジェクトを返すことができます。これで、私はもっと直感的に操作できるオブジェクトを得ることができます。

ロール機能

import pandas as pd 
import numpy as np 

def roll(df, w): 
    roll_array = np.dstack([df.values[i:i+w, :] for i in range(len(df.index) - w + 1)]).T 
    panel = pd.Panel(roll_array, 
        items=df.index[w-1:], 
        major_axis=df.columns, 
        minor_axis=pd.Index(range(w), name='roll')) 
    return panel.to_frame().unstack().T.groupby(level=0) 

デモンストレーション

np.random.seed([3,1415]) 
df = pd.DataFrame(np.random.rand(5, 2).round(2), columns=['A', 'B']) 

print df 

     A  B 
0 0.44 0.41 
1 0.46 0.47 
2 0.46 0.02 
3 0.85 0.82 
4 0.78 0.76 

レッツ・sum

rolled_df = roll(df, 2) 

print rolled_df.sum() 

major  A  B 
1  0.90 0.88 
2  0.92 0.49 
3  1.31 0.84 
4  1.63 1.58 

ボンネットの下を覗き見するために、我々はstucture見ることができます:

print rolled_df.apply(lambda x: x) 

major  A  B 
    roll    
1 0  0.44 0.41 
    1  0.46 0.47 
2 0  0.46 0.47 
    1  0.46 0.02 
3 0  0.46 0.02 
    1  0.85 0.82 
4 0  0.85 0.82 
    1  0.78 0.76 
0123を

しかし、私がこれを構築した目的は何ですか?しかし、私は今行列の乗算を解決します。

get_sliding_window(df, 2).dot(X) # window size = 2 

ランタイムテスト - - strides views concept on dataframe、ここではベクトル化されたアプローチだ使い方

X = np.array([2, 3]) 

print rolled_df.apply(lambda df: pd.Series(df.values.dot(X))) 

     0  1 
1 2.11 2.33 
2 2.33 0.98 
3 0.98 4.16 
4 4.16 3.84 
+0

これは非常に役に立ちました、ありがとう。私はnan値で少し問題に遭遇しましたが、 'roll'関数の最後の行を' .to_frame(filter_observations = False) 'を使用して更新すると、私の問題が修正されました。 – user338714

+0

これは参考になります。しかし、「ロール」列を元のインデックスに維持する方法はありますか?例えば0.46 0.47は常に「1」に関連付けられます。ありがとうございました。 – iwbabn

1

def roll(df, w): 
    roll_array = np.dstack([df.values[i:i+w, :] for i in range(len(df.index) - w + 1)]).T 
    roll_array_full_window = np.vstack((np.empty((w-1 ,len(df.columns), w)), roll_array)) 
    panel = pd.Panel(roll_array_full_window, 
       items=df.index, 
       major_axis=df.columns, 
       minor_axis=pd.Index(range(w), name='roll')) 
    return panel.to_frame().unstack().T.groupby(level=0) 
関連する問題