5
5
from __future__ import division
6
6
7
7
from functools import wraps
8
+ from collections import defaultdict
8
9
9
10
from numpy import NaN
10
11
import numpy as np
11
12
12
13
from pandas .core .api import DataFrame , Series , Panel , notnull
13
14
import pandas .algos as algos
14
- import pandas .core .common as com
15
- from pandas .core .common import _values_from_object
15
+ import pandas .core .common as pdcom
16
16
17
17
from pandas .util .decorators import Substitution , Appender
18
18
19
19
__all__ = ['rolling_count' , 'rolling_max' , 'rolling_min' ,
20
20
'rolling_sum' , 'rolling_mean' , 'rolling_std' , 'rolling_cov' ,
21
21
'rolling_corr' , 'rolling_var' , 'rolling_skew' , 'rolling_kurt' ,
22
22
'rolling_quantile' , 'rolling_median' , 'rolling_apply' ,
23
- 'rolling_cov_pairwise' , ' rolling_corr_pairwise' , 'rolling_window' ,
23
+ 'rolling_corr_pairwise' , 'rolling_window' ,
24
24
'ewma' , 'ewmvar' , 'ewmstd' , 'ewmvol' , 'ewmcorr' , 'ewmcov' ,
25
- 'ewmcorr_pairwise' , 'ewmcov_pairwise' ,
26
25
'expanding_count' , 'expanding_max' , 'expanding_min' ,
27
26
'expanding_sum' , 'expanding_mean' , 'expanding_std' ,
28
27
'expanding_cov' , 'expanding_corr' , 'expanding_var' ,
29
28
'expanding_skew' , 'expanding_kurt' , 'expanding_quantile' ,
30
- 'expanding_median' , 'expanding_apply' ,
31
- 'expanding_cov_pairwise' , 'expanding_corr_pairwise' ]
29
+ 'expanding_median' , 'expanding_apply' , 'expanding_corr_pairwise' ]
32
30
33
31
#------------------------------------------------------------------------------
34
32
# Docs
@@ -203,25 +201,43 @@ def rolling_count(arg, window, freq=None, center=False, time_rule=None):
203
201
204
202
@Substitution ("Unbiased moving covariance." , _binary_arg_flex , _flex_retval )
205
203
@Appender (_doc_template )
206
- def rolling_cov (arg1 , arg2 , window , min_periods = None , freq = None ,
207
- center = False , time_rule = None ):
204
+ def rolling_cov (arg1 , arg2 = None , window = None , min_periods = None , freq = None ,
205
+ center = False , time_rule = None , pairwise = None ):
206
+ if window is None and isinstance (arg2 , (int , float )):
207
+ window = arg2
208
+ arg2 = arg1
209
+ pairwise = True if pairwise is None else pairwise # only default unset
210
+ elif arg2 is None :
211
+ arg2 = arg1
212
+ pairwise = True if pairwise is None else pairwise # only default unset
208
213
arg1 = _conv_timerule (arg1 , freq , time_rule )
209
214
arg2 = _conv_timerule (arg2 , freq , time_rule )
210
215
window = min (window , len (arg1 ), len (arg2 ))
211
216
212
217
def _get_cov (X , Y ):
213
- mean = lambda x : rolling_mean (x , window , min_periods ,center = center )
214
- count = rolling_count (X + Y , window ,center = center )
218
+ mean = lambda x : rolling_mean (x , window , min_periods , center = center )
219
+ count = rolling_count (X + Y , window , center = center )
215
220
bias_adj = count / (count - 1 )
216
221
return (mean (X * Y ) - mean (X ) * mean (Y )) * bias_adj
217
- rs = _flex_binary_moment (arg1 , arg2 , _get_cov )
222
+ rs = _flex_binary_moment (arg1 , arg2 , _get_cov , pairwise = bool ( pairwise ) )
218
223
return rs
219
224
220
225
221
226
@Substitution ("Moving sample correlation." , _binary_arg_flex , _flex_retval )
222
227
@Appender (_doc_template )
223
- def rolling_corr (arg1 , arg2 , window , min_periods = None , freq = None ,
224
- center = False , time_rule = None ):
228
+ def rolling_corr (arg1 , arg2 = None , window = None , min_periods = None , freq = None ,
229
+ center = False , time_rule = None , pairwise = None ):
230
+ if window is None and isinstance (arg2 , (int , float )):
231
+ window = arg2
232
+ arg2 = arg1
233
+ pairwise = True if pairwise is None else pairwise # only default unset
234
+ elif arg2 is None :
235
+ arg2 = arg1
236
+ pairwise = True if pairwise is None else pairwise # only default unset
237
+ arg1 = _conv_timerule (arg1 , freq , time_rule )
238
+ arg2 = _conv_timerule (arg2 , freq , time_rule )
239
+ window = min (window , len (arg1 ), len (arg2 ))
240
+
225
241
def _get_corr (a , b ):
226
242
num = rolling_cov (a , b , window , min_periods , freq = freq ,
227
243
center = center , time_rule = time_rule )
@@ -230,10 +246,10 @@ def _get_corr(a, b):
230
246
rolling_std (b , window , min_periods , freq = freq ,
231
247
center = center , time_rule = time_rule ))
232
248
return num / den
233
- return _flex_binary_moment (arg1 , arg2 , _get_corr )
249
+ return _flex_binary_moment (arg1 , arg2 , _get_corr , pairwise = bool ( pairwise ) )
234
250
235
251
236
- def _flex_binary_moment (arg1 , arg2 , f ):
252
+ def _flex_binary_moment (arg1 , arg2 , f , pairwise = False ):
237
253
if not (isinstance (arg1 ,(np .ndarray , Series , DataFrame )) and
238
254
isinstance (arg2 ,(np .ndarray , Series , DataFrame ))):
239
255
raise TypeError ("arguments to moment function must be of type "
@@ -249,10 +265,23 @@ def _flex_binary_moment(arg1, arg2, f):
249
265
X , Y = arg1 .align (arg2 , join = 'outer' )
250
266
X = X + 0 * Y
251
267
Y = Y + 0 * X
252
- res_columns = arg1 .columns .union (arg2 .columns )
253
- for col in res_columns :
254
- if col in X and col in Y :
255
- results [col ] = f (X [col ], Y [col ])
268
+ if pairwise is False :
269
+ res_columns = arg1 .columns .union (arg2 .columns )
270
+ for col in res_columns :
271
+ if col in X and col in Y :
272
+ results [col ] = f (X [col ], Y [col ])
273
+ elif pairwise is True :
274
+ results = defaultdict (dict )
275
+ for i , k1 in enumerate (arg1 .columns ):
276
+ for j , k2 in enumerate (arg2 .columns ):
277
+ if j < i and arg2 is arg1 :
278
+ # Symmetric case
279
+ results [k1 ][k2 ] = results [k2 ][k1 ]
280
+ else :
281
+ results [k1 ][k2 ] = f (arg1 [k1 ], arg2 [k2 ])
282
+ return Panel .from_dict (results ).swapaxes ('items' , 'major' )
283
+ else :
284
+ raise ValueError ("'pairwise' is not True/False" )
256
285
else :
257
286
res_columns = arg1 .columns
258
287
X , Y = arg1 .align (arg2 , axis = 0 , join = 'outer' )
@@ -266,53 +295,14 @@ def _flex_binary_moment(arg1, arg2, f):
266
295
return _flex_binary_moment (arg2 , arg1 , f )
267
296
268
297
269
- def _flex_pairwise_moment (moment_func , df1 , df2 , ** kwargs ):
270
- from collections import defaultdict
271
-
272
- # Detect symmetry
273
- if df2 is df1 :
274
- symmetric = True
275
- else :
276
- symmetric = False
277
-
278
- all_results = defaultdict (dict )
279
-
280
- for i , k1 in enumerate (df1 .columns ):
281
- for j , k2 in enumerate (df2 .columns ):
282
- if j < i and symmetric :
283
- all_results [k1 ][k2 ] = all_results [k2 ][k1 ]
284
- else :
285
- all_results [k1 ][k2 ] = moment_func (df1 [k1 ], df2 [k2 ], ** kwargs )
286
-
287
- return Panel .from_dict (all_results ).swapaxes ('items' , 'major' )
288
-
289
-
290
- @Substitution ("Pairwise unbiased moving covariance" , _pairwise_arg ,
291
- _pairwise_retval )
292
- @Appender (_doc_template )
293
- def rolling_cov_pairwise (df1 , df2 , window = None , min_periods = None , freq = None ,
294
- center = False , time_rule = None ):
295
- # Try to preserve the previous API
296
- if window is None and isinstance (df2 , (int , float )):
297
- window = df2
298
- df2 = df1
299
- return _flex_pairwise_moment (rolling_cov , df1 , df2 , window = window ,
300
- min_periods = min_periods , freq = freq ,
301
- center = center , time_rule = time_rule )
302
-
303
-
304
298
@Substitution ("Pairwise moving sample correlation" , _pairwise_arg ,
305
299
_pairwise_retval )
306
300
@Appender (_doc_template )
307
- def rolling_corr_pairwise (df1 , df2 , window = None , min_periods = None , freq = None ,
308
- center = False , time_rule = None ):
309
- # Try to preserve the previous API
310
- if window is None and isinstance (df2 , (int , float )):
311
- window = df2
312
- df2 = df1
313
- return _flex_pairwise_moment (rolling_corr , df1 , df2 , window = window ,
314
- min_periods = min_periods , freq = freq ,
315
- center = center , time_rule = time_rule )
301
+ def rolling_corr_pairwise (df1 , df2 = None , window = None , min_periods = None ,
302
+ freq = None , center = False , time_rule = None ):
303
+ return rolling_corr (df1 , df2 , window = window , min_periods = min_periods ,
304
+ freq = freq , center = center , time_rule = time_rule ,
305
+ pairwise = True )
316
306
317
307
318
308
def _rolling_moment (arg , window , func , minp , axis = 0 , freq = None , center = False ,
@@ -361,7 +351,8 @@ def _rolling_moment(arg, window, func, minp, axis=0, freq=None, center=False,
361
351
362
352
def _center_window (rs , window , axis ):
363
353
if axis > rs .ndim - 1 :
364
- raise ValueError ("Requested axis is larger then no. of argument dimensions" )
354
+ raise ValueError ("Requested axis is larger then no. of argument "
355
+ "dimensions" )
365
356
366
357
offset = int ((window - 1 ) / 2. )
367
358
if isinstance (rs , (Series , DataFrame , Panel )):
@@ -480,61 +471,55 @@ def ewmstd(arg, com=None, span=None, halflife=None, min_periods=0, bias=False,
480
471
@Substitution ("Exponentially-weighted moving covariance" , _binary_arg , "" ,
481
472
_type_of_input )
482
473
@Appender (_ewm_doc )
483
- def ewmcov (arg1 , arg2 , com = None , span = None , halflife = None , min_periods = 0 , bias = False ,
484
- freq = None , time_rule = None ):
474
+ def ewmcov (arg1 , arg2 = None , com = None , span = None , halflife = None , min_periods = 0 , bias = False ,
475
+ freq = None , time_rule = None , pairwise = None ):
476
+ if arg2 is None :
477
+ arg2 = arg1
478
+ pairwise = True if pairwise is None else pairwise
479
+ elif isinstance (arg2 , (int , float )) and com is None :
480
+ com = arg2
481
+ arg2 = arg1
482
+ pairwise = True if pairwise is None else pairwise
485
483
arg1 = _conv_timerule (arg1 , freq , time_rule )
486
484
arg2 = _conv_timerule (arg2 , freq , time_rule )
487
485
488
486
def _get_ewmcov (X , Y ):
489
487
mean = lambda x : ewma (x , com = com , span = span , halflife = halflife , min_periods = min_periods )
490
488
return (mean (X * Y ) - mean (X ) * mean (Y ))
491
- result = _flex_binary_moment (arg1 , arg2 , _get_ewmcov )
489
+ result = _flex_binary_moment (arg1 , arg2 , _get_ewmcov ,
490
+ pairwise = bool (pairwise ))
492
491
if not bias :
493
492
com = _get_center_of_mass (com , span , halflife )
494
493
result *= (1.0 + 2.0 * com ) / (2.0 * com )
495
494
496
495
return result
497
496
498
497
499
- @Substitution ("Pairwise exponentially-weighted moving covariance" ,
500
- _pairwise_arg , "" , _pairwise_retval )
501
- @Appender (_ewm_doc )
502
- def ewmcov_pairwise (df1 , df2 = None , com = None , span = None , min_periods = 0 ,
503
- bias = False , freq = None , time_rule = None ):
504
- if df2 is None :
505
- df2 = df1
506
- return _flex_pairwise_moment (ewmcov , df1 , df2 , com = com , span = span ,
507
- min_periods = min_periods , bias = bias , freq = freq , time_rule = time_rule )
508
-
509
-
510
498
@Substitution ("Exponentially-weighted moving correlation" , _binary_arg , "" ,
511
499
_type_of_input )
512
500
@Appender (_ewm_doc )
513
- def ewmcorr (arg1 , arg2 , com = None , span = None , halflife = None , min_periods = 0 ,
514
- freq = None , time_rule = None ):
501
+ def ewmcorr (arg1 , arg2 = None , com = None , span = None , halflife = None , min_periods = 0 ,
502
+ freq = None , time_rule = None , pairwise = None ):
503
+ if arg2 is None :
504
+ arg2 = arg1
505
+ pairwise = True if pairwise is None else pairwise
506
+ elif isinstance (arg2 , (int , float )) and com is None :
507
+ com = arg2
508
+ arg2 = arg1
509
+ pairwise = True if pairwise is None else pairwise
515
510
arg1 = _conv_timerule (arg1 , freq , time_rule )
516
511
arg2 = _conv_timerule (arg2 , freq , time_rule )
517
512
518
513
def _get_ewmcorr (X , Y ):
519
514
mean = lambda x : ewma (x , com = com , span = span , halflife = halflife , min_periods = min_periods )
520
515
var = lambda x : ewmvar (x , com = com , span = span , halflife = halflife , min_periods = min_periods ,
521
- bias = True )
516
+ bias = True )
522
517
return (mean (X * Y ) - mean (X ) * mean (Y )) / _zsqrt (var (X ) * var (Y ))
523
- result = _flex_binary_moment (arg1 , arg2 , _get_ewmcorr )
518
+ result = _flex_binary_moment (arg1 , arg2 , _get_ewmcorr ,
519
+ pairwise = bool (pairwise ))
524
520
return result
525
521
526
522
527
- @Substitution ("Pairwise exponentially-weighted moving correlation" ,
528
- _pairwise_arg , "" , _pairwise_retval )
529
- @Appender (_ewm_doc )
530
- def ewmcorr_pairwise (df1 , df2 = None , com = None , span = None , min_periods = 0 ,
531
- freq = None , time_rule = None ):
532
- if df2 is None :
533
- df2 = df1
534
- return _flex_pairwise_moment (ewmcorr , df1 , df2 , com = com , span = span ,
535
- min_periods = min_periods , freq = freq , time_rule = time_rule )
536
-
537
-
538
523
def _zsqrt (x ):
539
524
result = np .sqrt (x )
540
525
mask = x < 0
@@ -779,8 +764,8 @@ def rolling_window(arg, window=None, win_type=None, min_periods=None,
779
764
if win_type is not None :
780
765
raise ValueError (('Do not specify window type if using custom '
781
766
'weights' ))
782
- window = com ._asarray_tuplesafe (window ).astype (float )
783
- elif com .is_integer (window ): # window size
767
+ window = pdcom ._asarray_tuplesafe (window ).astype (float )
768
+ elif pdcom .is_integer (window ): # window size
784
769
if win_type is None :
785
770
raise ValueError ('Must specify window type' )
786
771
try :
@@ -928,46 +913,47 @@ def expanding_quantile(arg, quantile, min_periods=1, freq=None,
928
913
929
914
@Substitution ("Unbiased expanding covariance." , _binary_arg_flex , _flex_retval )
930
915
@Appender (_expanding_doc )
931
- def expanding_cov (arg1 , arg2 , min_periods = 1 , freq = None , center = False ,
932
- time_rule = None ):
916
+ def expanding_cov (arg1 , arg2 = None , min_periods = 1 , freq = None , center = False ,
917
+ time_rule = None , pairwise = None ):
918
+ if arg2 is None :
919
+ arg2 = arg1
920
+ pairwise = True if pairwise is None else pairwise
921
+ elif isinstance (arg2 , (int , float )) and min_periods is None :
922
+ min_periods = arg2
923
+ arg2 = arg1
924
+ pairwise = True if pairwise is None else pairwise
933
925
window = max (len (arg1 ), len (arg2 ))
934
926
return rolling_cov (arg1 , arg2 , window ,
935
927
min_periods = min_periods , freq = freq ,
936
- center = center , time_rule = time_rule )
937
-
938
-
939
- @Substitution ("Pairwise unbiased expanding covariance" , _pairwise_arg ,
940
- _pairwise_retval )
941
- @Appender (_expanding_doc )
942
- def expanding_cov_pairwise (df1 , df2 = None , min_periods = 1 , freq = None ,
943
- center = False , time_rule = None ):
944
- if df2 is None :
945
- df2 = df1
946
- return _flex_pairwise_moment (expanding_cov , df1 , df2 ,
947
- min_periods = min_periods , freq = freq ,
948
- center = center , time_rule = time_rule )
928
+ center = center , time_rule = time_rule , pairwise = pairwise )
949
929
950
930
951
931
@Substitution ("Expanding sample correlation." , _binary_arg_flex , _flex_retval )
952
932
@Appender (_expanding_doc )
953
- def expanding_corr (arg1 , arg2 , min_periods = 1 , freq = None , center = False ,
954
- time_rule = None ):
933
+ def expanding_corr (arg1 , arg2 = None , min_periods = 1 , freq = None , center = False ,
934
+ time_rule = None , pairwise = None ):
935
+ if arg2 is None :
936
+ arg2 = arg1
937
+ pairwise = True if pairwise is None else pairwise
938
+ elif isinstance (arg2 , (int , float )) and min_periods is None :
939
+ min_periods = arg2
940
+ arg2 = arg1
941
+ pairwise = True if pairwise is None else pairwise
955
942
window = max (len (arg1 ), len (arg2 ))
956
943
return rolling_corr (arg1 , arg2 , window ,
957
944
min_periods = min_periods ,
958
- freq = freq , center = center , time_rule = time_rule )
945
+ freq = freq , center = center , time_rule = time_rule ,
946
+ pairwise = pairwise )
959
947
960
948
961
949
@Substitution ("Pairwise expanding sample correlation" , _pairwise_arg ,
962
950
_pairwise_retval )
963
951
@Appender (_expanding_doc )
964
952
def expanding_corr_pairwise (df1 , df2 = None , min_periods = 1 , freq = None ,
965
953
center = False , time_rule = None ):
966
- if df2 is None :
967
- df2 = df1
968
- return _flex_pairwise_moment (expanding_corr , df1 , df2 ,
969
- min_periods = min_periods , freq = freq ,
970
- center = center , time_rule = time_rule )
954
+ return expanding_corr (df1 , df2 , min_periods = min_periods ,
955
+ freq = freq , center = center , time_rule = time_rule ,
956
+ pairwise = True )
971
957
972
958
973
959
def expanding_apply (arg , func , min_periods = 1 , freq = None , center = False ,
0 commit comments