@@ -678,7 +678,7 @@ def test_groupby_rolling_nans_in_index(self, rollings, key):
678678 )
679679 if key == "index" :
680680 df = df .set_index ("a" )
681- with pytest .raises (ValueError , match = f"{ key } must be monotonic " ):
681+ with pytest .raises (ValueError , match = f"{ key } must not have any NaT values " ):
682682 df .groupby ("c" ).rolling ("60min" , ** rollings )
683683
684684 @pytest .mark .parametrize ("group_keys" , [True , False ])
@@ -922,6 +922,83 @@ def test_nan_and_zero_endpoints(self):
922922 )
923923 tm .assert_series_equal (result , expected )
924924
925+ def test_groupby_rolling_non_monotonic (self ):
926+ # GH 43909
927+
928+ shuffled = [3 , 0 , 1 , 2 ]
929+ sec = 1_000
930+ df = DataFrame (
931+ [{"t" : Timestamp (2 * x * sec ), "x" : x + 1 , "c" : 42 } for x in shuffled ]
932+ )
933+ with pytest .raises (ValueError , match = r".* must be monotonic" ):
934+ df .groupby ("c" ).rolling (on = "t" , window = "3s" )
935+
936+ def test_groupby_monotonic (self ):
937+
938+ # GH 15130
939+ # we don't need to validate monotonicity when grouping
940+
941+ # GH 43909 we should raise an error here to match
942+ # behaviour of non-groupby rolling.
943+
944+ data = [
945+ ["David" , "1/1/2015" , 100 ],
946+ ["David" , "1/5/2015" , 500 ],
947+ ["David" , "5/30/2015" , 50 ],
948+ ["David" , "7/25/2015" , 50 ],
949+ ["Ryan" , "1/4/2014" , 100 ],
950+ ["Ryan" , "1/19/2015" , 500 ],
951+ ["Ryan" , "3/31/2016" , 50 ],
952+ ["Joe" , "7/1/2015" , 100 ],
953+ ["Joe" , "9/9/2015" , 500 ],
954+ ["Joe" , "10/15/2015" , 50 ],
955+ ]
956+
957+ df = DataFrame (data = data , columns = ["name" , "date" , "amount" ])
958+ df ["date" ] = to_datetime (df ["date" ])
959+ df = df .sort_values ("date" )
960+
961+ expected = (
962+ df .set_index ("date" )
963+ .groupby ("name" )
964+ .apply (lambda x : x .rolling ("180D" )["amount" ].sum ())
965+ )
966+ result = df .groupby ("name" ).rolling ("180D" , on = "date" )["amount" ].sum ()
967+ tm .assert_series_equal (result , expected )
968+
969+ def test_datelike_on_monotonic_within_each_group (self ):
970+ # GH 13966 (similar to #15130, closed by #15175)
971+
972+ # superseded by 43909
973+ # GH 46061: OK if the on is monotonic relative to each each group
974+
975+ dates = date_range (start = "2016-01-01 09:30:00" , periods = 20 , freq = "s" )
976+ df = DataFrame (
977+ {
978+ "A" : [1 ] * 20 + [2 ] * 12 + [3 ] * 8 ,
979+ "B" : np .concatenate ((dates , dates )),
980+ "C" : np .arange (40 ),
981+ }
982+ )
983+
984+ expected = (
985+ df .set_index ("B" ).groupby ("A" ).apply (lambda x : x .rolling ("4s" )["C" ].mean ())
986+ )
987+ result = df .groupby ("A" ).rolling ("4s" , on = "B" ).C .mean ()
988+ tm .assert_series_equal (result , expected )
989+
990+ def test_datelike_on_not_monotonic_within_each_group (self ):
991+ # GH 46061
992+ df = DataFrame (
993+ {
994+ "A" : [1 ] * 3 + [2 ] * 3 ,
995+ "B" : [Timestamp (year , 1 , 1 ) for year in [2020 , 2021 , 2019 ]] * 2 ,
996+ "C" : range (6 ),
997+ }
998+ )
999+ with pytest .raises (ValueError , match = "Each group within B must be monotonic." ):
1000+ df .groupby ("A" ).rolling ("365D" , on = "B" )
1001+
9251002
9261003class TestExpanding :
9271004 def setup_method (self ):
0 commit comments