@@ -1072,7 +1072,13 @@ def mklbl(prefix,n):
10721072 ix = MultiIndex .from_product ([mklbl ('A' ,5 ),mklbl ('B' ,7 ),mklbl ('C' ,4 ),mklbl ('D' ,2 )])
10731073 df = DataFrame (np .arange (len (ix .get_values ())),index = ix )
10741074 result = df .loc [(slice ('A1' ,'A3' ),slice (None ), ['C1' ,'C3' ]),:]
1075- expected = df .loc [[ tuple ([a ,b ,c ,d ]) for a ,b ,c ,d in df .index .values if (a == 'A1' or a == 'A2' ) and (c == 'C1' or c == 'C3' )]]
1075+ expected = df .loc [[ tuple ([a ,b ,c ,d ]) for a ,b ,c ,d in df .index .values if (
1076+ a == 'A1' or a == 'A2' or a == 'A3' ) and (c == 'C1' or c == 'C3' )]]
1077+ assert_frame_equal (result , expected )
1078+
1079+ expected = df .loc [[ tuple ([a ,b ,c ,d ]) for a ,b ,c ,d in df .index .values if (
1080+ a == 'A1' or a == 'A2' or a == 'A3' ) and (c == 'C1' or c == 'C2' or c == 'C3' )]]
1081+ result = df .loc [(slice ('A1' ,'A3' ),slice (None ), slice ('C1' ,'C3' )),:]
10761082 assert_frame_equal (result , expected )
10771083
10781084 # test multi-index slicing with per axis and per index controls
@@ -1121,13 +1127,164 @@ def mklbl(prefix,n):
11211127 expected = df .iloc [[0 ,1 ,3 ]]
11221128 assert_frame_equal (result , expected )
11231129
1130+ # multi-level series
1131+ s = Series (np .arange (len (ix .get_values ())),index = ix )
1132+ result = s .loc ['A1' :'A3' , :, ['C1' ,'C3' ]]
1133+ expected = s .loc [[ tuple ([a ,b ,c ,d ]) for a ,b ,c ,d in s .index .values if (
1134+ a == 'A1' or a == 'A2' or a == 'A3' ) and (c == 'C1' or c == 'C3' )]]
1135+ assert_series_equal (result , expected )
1136+
1137+ # boolean indexers
1138+ result = df .loc [(slice (None ),df .loc [:,('a' ,'bar' )]> 5 ),:]
1139+ expected = df .iloc [[2 ,3 ]]
1140+ assert_frame_equal (result , expected )
1141+
1142+ def f ():
1143+ df .loc [(slice (None ),np .array ([True ,False ])),:]
1144+ self .assertRaises (ValueError , f )
1145+
11241146 # ambiguous cases
11251147 # these can be multiply interpreted
11261148 # but we can catch this in some cases
11271149 def f ():
11281150 df .loc [(slice (None ),[1 ])]
11291151 self .assertRaises (KeyError , f )
11301152
1153+ def test_per_axis_per_level_getitem_doc_examples (self ):
1154+
1155+ # from indexing.rst / advanced
1156+ def mklbl (prefix ,n ):
1157+ return ["%s%s" % (prefix ,i ) for i in range (n )]
1158+
1159+ index = MultiIndex .from_product ([mklbl ('A' ,4 ),
1160+ mklbl ('B' ,2 ),
1161+ mklbl ('C' ,4 ),
1162+ mklbl ('D' ,2 )])
1163+ columns = MultiIndex .from_tuples ([('a' ,'foo' ),('a' ,'bar' ),
1164+ ('b' ,'foo' ),('b' ,'bah' )],
1165+ names = ['lvl0' , 'lvl1' ])
1166+ df = DataFrame (np .arange (len (index )* len (columns )).reshape ((len (index ),len (columns ))),
1167+ index = index ,
1168+ columns = columns )
1169+ result = df .loc [(slice ('A1' ,'A3' ),slice (None ), ['C1' ,'C3' ]),:]
1170+ expected = df .loc [[ tuple ([a ,b ,c ,d ]) for a ,b ,c ,d in df .index .values if (
1171+ a == 'A1' or a == 'A2' or a == 'A3' ) and (c == 'C1' or c == 'C3' )]]
1172+ assert_frame_equal (result , expected )
1173+
1174+ result = df .loc [(slice (None ),slice (None ), ['C1' ,'C3' ]),:]
1175+ expected = df .loc [[ tuple ([a ,b ,c ,d ]) for a ,b ,c ,d in df .index .values if (
1176+ c == 'C1' or c == 'C3' )]]
1177+ assert_frame_equal (result , expected )
1178+
1179+ # not sorted
1180+ def f ():
1181+ df .loc ['A1' ,(slice (None ),'foo' )]
1182+ self .assertRaises (KeyError , f )
1183+ df = df .sortlevel (axis = 1 )
1184+
1185+ df .loc ['A1' ,(slice (None ),'foo' )]
1186+ df .loc [(slice (None ),slice (None ), ['C1' ,'C3' ]),(slice (None ),'foo' )]
1187+
1188+ def test_per_axis_per_level_setitem (self ):
1189+
1190+ # test multi-index slicing with per axis and per index controls
1191+ index = MultiIndex .from_tuples ([('A' ,1 ),('A' ,2 ),('A' ,3 ),('B' ,1 )],
1192+ names = ['one' ,'two' ])
1193+ columns = MultiIndex .from_tuples ([('a' ,'foo' ),('a' ,'bar' ),('b' ,'foo' ),('b' ,'bah' )],
1194+ names = ['lvl0' , 'lvl1' ])
1195+
1196+ df_orig = DataFrame (np .arange (16 ).reshape (4 , 4 ), index = index , columns = columns )
1197+ df_orig = df_orig .sortlevel (axis = 0 ).sortlevel (axis = 1 )
1198+
1199+ # identity
1200+ df = df_orig .copy ()
1201+ df .loc [(slice (None ),slice (None )),:] = 100
1202+ expected = df_orig .copy ()
1203+ expected .iloc [:,:] = 100
1204+ assert_frame_equal (df , expected )
1205+
1206+ df = df_orig .copy ()
1207+ df .loc [(slice (None ),slice (None )),(slice (None ),slice (None ))] = 100
1208+ expected = df_orig .copy ()
1209+ expected .iloc [:,:] = 100
1210+ assert_frame_equal (df , expected )
1211+
1212+ df = df_orig .copy ()
1213+ df .loc [:,(slice (None ),slice (None ))] = 100
1214+ expected = df_orig .copy ()
1215+ expected .iloc [:,:] = 100
1216+ assert_frame_equal (df , expected )
1217+
1218+ # index
1219+ df = df_orig .copy ()
1220+ df .loc [(slice (None ),[1 ]),:] = 100
1221+ expected = df_orig .copy ()
1222+ expected .iloc [[0 ,3 ]] = 100
1223+ assert_frame_equal (df , expected )
1224+
1225+ df = df_orig .copy ()
1226+ df .loc [(slice (None ),1 ),:] = 100
1227+ expected = df_orig .copy ()
1228+ expected .iloc [[0 ,3 ]] = 100
1229+ assert_frame_equal (df , expected )
1230+
1231+ # columns
1232+ df = df_orig .copy ()
1233+ df .loc [:,(slice (None ),['foo' ])] = 100
1234+ expected = df_orig .copy ()
1235+ expected .iloc [:,[1 ,3 ]] = 100
1236+ assert_frame_equal (df , expected )
1237+
1238+ # both
1239+ df = df_orig .copy ()
1240+ df .loc [(slice (None ),1 ),(slice (None ),['foo' ])] = 100
1241+ expected = df_orig .copy ()
1242+ expected .iloc [[0 ,3 ],[1 ,3 ]] = 100
1243+ assert_frame_equal (df , expected )
1244+
1245+ df = df_orig .copy ()
1246+ df .loc ['A' ,'a' ] = 100
1247+ expected = df_orig .copy ()
1248+ expected .iloc [0 :3 ,0 :2 ] = 100
1249+ assert_frame_equal (df , expected )
1250+
1251+ # setting with a list-like
1252+ df = df_orig .copy ()
1253+ df .loc [(slice (None ),1 ),(slice (None ),['foo' ])] = np .array ([[100 , 100 ], [100 , 100 ]],dtype = 'int64' )
1254+ expected = df_orig .copy ()
1255+ expected .iloc [[0 ,3 ],[1 ,3 ]] = 100
1256+ assert_frame_equal (df , expected )
1257+
1258+ # not enough values
1259+ df = df_orig .copy ()
1260+ def f ():
1261+ df .loc [(slice (None ),1 ),(slice (None ),['foo' ])] = np .array ([[100 ], [100 , 100 ]],dtype = 'int64' )
1262+ self .assertRaises (ValueError , f )
1263+ def f ():
1264+ df .loc [(slice (None ),1 ),(slice (None ),['foo' ])] = np .array ([100 , 100 , 100 , 100 ],dtype = 'int64' )
1265+ self .assertRaises (ValueError , f )
1266+
1267+ # with an alignable rhs
1268+ df = df_orig .copy ()
1269+ df .loc [(slice (None ),1 ),(slice (None ),['foo' ])] = df .loc [(slice (None ),1 ),(slice (None ),['foo' ])] * 5
1270+ expected = df_orig .copy ()
1271+ expected .iloc [[0 ,3 ],[1 ,3 ]] = expected .iloc [[0 ,3 ],[1 ,3 ]] * 5
1272+ assert_frame_equal (df , expected )
1273+
1274+ df = df_orig .copy ()
1275+ df .loc [(slice (None ),1 ),(slice (None ),['foo' ])] *= df .loc [(slice (None ),1 ),(slice (None ),['foo' ])]
1276+ expected = df_orig .copy ()
1277+ expected .iloc [[0 ,3 ],[1 ,3 ]] *= expected .iloc [[0 ,3 ],[1 ,3 ]]
1278+ assert_frame_equal (df , expected )
1279+
1280+ rhs = df_orig .loc [(slice (None ),1 ),(slice (None ),['foo' ])].copy ()
1281+ rhs .loc [:,('c' ,'bah' )] = 10
1282+ df = df_orig .copy ()
1283+ df .loc [(slice (None ),1 ),(slice (None ),['foo' ])] *= rhs
1284+ expected = df_orig .copy ()
1285+ expected .iloc [[0 ,3 ],[1 ,3 ]] *= expected .iloc [[0 ,3 ],[1 ,3 ]]
1286+ assert_frame_equal (df , expected )
1287+
11311288 def test_getitem_multiindex (self ):
11321289
11331290 # GH 5725
0 commit comments