@@ -1072,7 +1072,13 @@ def mklbl(prefix,n):
1072
1072
ix = MultiIndex .from_product ([mklbl ('A' ,5 ),mklbl ('B' ,7 ),mklbl ('C' ,4 ),mklbl ('D' ,2 )])
1073
1073
df = DataFrame (np .arange (len (ix .get_values ())),index = ix )
1074
1074
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' )),:]
1076
1082
assert_frame_equal (result , expected )
1077
1083
1078
1084
# test multi-index slicing with per axis and per index controls
@@ -1121,13 +1127,164 @@ def mklbl(prefix,n):
1121
1127
expected = df .iloc [[0 ,1 ,3 ]]
1122
1128
assert_frame_equal (result , expected )
1123
1129
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
+
1124
1146
# ambiguous cases
1125
1147
# these can be multiply interpreted
1126
1148
# but we can catch this in some cases
1127
1149
def f ():
1128
1150
df .loc [(slice (None ),[1 ])]
1129
1151
self .assertRaises (KeyError , f )
1130
1152
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
+
1131
1288
def test_getitem_multiindex (self ):
1132
1289
1133
1290
# GH 5725
0 commit comments