@@ -362,36 +362,69 @@ def nlevels(self):
362
362
def _get_names (self ):
363
363
return FrozenList ((self .name ,))
364
364
365
- def _set_names (self , values ):
365
+ def _set_names (self , values , level = None ):
366
366
if len (values ) != 1 :
367
367
raise ValueError ('Length of new names must be 1, got %d'
368
368
% len (values ))
369
369
self .name = values [0 ]
370
370
371
371
names = property (fset = _set_names , fget = _get_names )
372
372
373
- def set_names (self , names , inplace = False ):
373
+ def set_names (self , names , level = None , inplace = False ):
374
374
"""
375
375
Set new names on index. Defaults to returning new index.
376
376
377
377
Parameters
378
378
----------
379
- names : sequence
380
- names to set
379
+ names : str or sequence
380
+ name(s) to set
381
+ level : int or level name, or sequence of int / level names (default None)
382
+ If the index is a MultiIndex (hierarchical), level(s) to set (None for all levels)
383
+ Otherwise level must be None
381
384
inplace : bool
382
385
if True, mutates in place
383
386
384
387
Returns
385
388
-------
386
389
new index (of same type and class...etc) [if inplace, returns None]
390
+
391
+ Examples
392
+ --------
393
+ >>> Index([1, 2, 3, 4]).set_names('foo')
394
+ Int64Index([1, 2, 3, 4], dtype='int64')
395
+ >>> Index([1, 2, 3, 4]).set_names(['foo'])
396
+ Int64Index([1, 2, 3, 4], dtype='int64')
397
+ >>> idx = MultiIndex.from_tuples([(1, u'one'), (1, u'two'),
398
+ (2, u'one'), (2, u'two')],
399
+ names=['foo', 'bar'])
400
+ >>> idx.set_names(['baz', 'quz'])
401
+ MultiIndex(levels=[[1, 2], [u'one', u'two']],
402
+ labels=[[0, 0, 1, 1], [0, 1, 0, 1]],
403
+ names=[u'baz', u'quz'])
404
+ >>> idx.set_names('baz', level=0)
405
+ MultiIndex(levels=[[1, 2], [u'one', u'two']],
406
+ labels=[[0, 0, 1, 1], [0, 1, 0, 1]],
407
+ names=[u'baz', u'bar'])
387
408
"""
388
- if not com .is_list_like (names ):
409
+ if level is not None and self .nlevels == 1 :
410
+ raise ValueError ('Level must be None for non-MultiIndex' )
411
+
412
+ if level is not None and not com .is_list_like (level ) and com .is_list_like (names ):
413
+ raise TypeError ("Names must be a string" )
414
+
415
+ if not com .is_list_like (names ) and level is None and self .nlevels > 1 :
389
416
raise TypeError ("Must pass list-like as `names`." )
417
+
418
+ if not com .is_list_like (names ):
419
+ names = [names ]
420
+ if level is not None and not com .is_list_like (level ):
421
+ level = [level ]
422
+
390
423
if inplace :
391
424
idx = self
392
425
else :
393
426
idx = self ._shallow_copy ()
394
- idx ._set_names (names )
427
+ idx ._set_names (names , level = level )
395
428
if not inplace :
396
429
return idx
397
430
@@ -2218,19 +2251,30 @@ def _verify_integrity(self):
2218
2251
def _get_levels (self ):
2219
2252
return self ._levels
2220
2253
2221
- def _set_levels (self , levels , copy = False , validate = True ,
2254
+ def _set_levels (self , levels , level = None , copy = False , validate = True ,
2222
2255
verify_integrity = False ):
2223
2256
# This is NOT part of the levels property because it should be
2224
2257
# externally not allowed to set levels. User beware if you change
2225
2258
# _levels directly
2226
2259
if validate and len (levels ) == 0 :
2227
2260
raise ValueError ('Must set non-zero number of levels.' )
2228
- if validate and len (levels ) != len (self ._labels ):
2229
- raise ValueError ('Length of levels must match length of labels.' )
2230
- levels = FrozenList (_ensure_index (lev , copy = copy )._shallow_copy ()
2231
- for lev in levels )
2261
+ if validate and level is None and len (levels ) != self .nlevels :
2262
+ raise ValueError ('Length of levels must match number of levels.' )
2263
+ if validate and level is not None and len (levels ) != len (level ):
2264
+ raise ValueError ('Length of levels must match length of level.' )
2265
+
2266
+ if level is None :
2267
+ new_levels = FrozenList (_ensure_index (lev , copy = copy )._shallow_copy ()
2268
+ for lev in levels )
2269
+ else :
2270
+ level = [self ._get_level_number (l ) for l in level ]
2271
+ new_levels = list (self ._levels )
2272
+ for l , v in zip (level , levels ):
2273
+ new_levels [l ] = _ensure_index (v , copy = copy )._shallow_copy ()
2274
+ new_levels = FrozenList (new_levels )
2275
+
2232
2276
names = self .names
2233
- self ._levels = levels
2277
+ self ._levels = new_levels
2234
2278
if any (names ):
2235
2279
self ._set_names (names )
2236
2280
@@ -2240,15 +2284,17 @@ def _set_levels(self, levels, copy=False, validate=True,
2240
2284
if verify_integrity :
2241
2285
self ._verify_integrity ()
2242
2286
2243
- def set_levels (self , levels , inplace = False , verify_integrity = True ):
2287
+ def set_levels (self , levels , level = None , inplace = False , verify_integrity = True ):
2244
2288
"""
2245
2289
Set new levels on MultiIndex. Defaults to returning
2246
2290
new index.
2247
2291
2248
2292
Parameters
2249
2293
----------
2250
- levels : sequence
2251
- new levels to apply
2294
+ levels : sequence or list of sequence
2295
+ new level(s) to apply
2296
+ level : int or level name, or sequence of int / level names (default None)
2297
+ level(s) to set (None for all levels)
2252
2298
inplace : bool
2253
2299
if True, mutates in place
2254
2300
verify_integrity : bool (default True)
@@ -2257,15 +2303,47 @@ def set_levels(self, levels, inplace=False, verify_integrity=True):
2257
2303
Returns
2258
2304
-------
2259
2305
new index (of same type and class...etc)
2260
- """
2261
- if not com .is_list_like (levels ) or not com .is_list_like (levels [0 ]):
2262
- raise TypeError ("Levels must be list of lists-like" )
2306
+
2307
+
2308
+ Examples
2309
+ --------
2310
+ >>> idx = MultiIndex.from_tuples([(1, u'one'), (1, u'two'),
2311
+ (2, u'one'), (2, u'two')],
2312
+ names=['foo', 'bar'])
2313
+ >>> idx.set_levels([['a','b'], [1,2]])
2314
+ MultiIndex(levels=[[u'a', u'b'], [1, 2]],
2315
+ labels=[[0, 0, 1, 1], [0, 1, 0, 1]],
2316
+ names=[u'foo', u'bar'])
2317
+ >>> idx.set_levels(['a','b'], level=0)
2318
+ MultiIndex(levels=[[u'a', u'b'], [u'one', u'two']],
2319
+ labels=[[0, 0, 1, 1], [0, 1, 0, 1]],
2320
+ names=[u'foo', u'bar'])
2321
+ >>> idx.set_levels(['a','b'], level='bar')
2322
+ MultiIndex(levels=[[1, 2], [u'a', u'b']],
2323
+ labels=[[0, 0, 1, 1], [0, 1, 0, 1]],
2324
+ names=[u'foo', u'bar'])
2325
+ >>> idx.set_levels([['a','b'], [1,2]], level=[0,1])
2326
+ MultiIndex(levels=[[u'a', u'b'], [1, 2]],
2327
+ labels=[[0, 0, 1, 1], [0, 1, 0, 1]],
2328
+ names=[u'foo', u'bar'])
2329
+ """
2330
+ if level is not None and not com .is_list_like (level ):
2331
+ if not com .is_list_like (levels ):
2332
+ raise TypeError ("Levels must be list-like" )
2333
+ if com .is_list_like (levels [0 ]):
2334
+ raise TypeError ("Levels must be list-like" )
2335
+ level = [level ]
2336
+ levels = [levels ]
2337
+ elif level is None or com .is_list_like (level ):
2338
+ if not com .is_list_like (levels ) or not com .is_list_like (levels [0 ]):
2339
+ raise TypeError ("Levels must be list of lists-like" )
2340
+
2263
2341
if inplace :
2264
2342
idx = self
2265
2343
else :
2266
2344
idx = self ._shallow_copy ()
2267
2345
idx ._reset_identity ()
2268
- idx ._set_levels (levels , validate = True ,
2346
+ idx ._set_levels (levels , level = level , validate = True ,
2269
2347
verify_integrity = verify_integrity )
2270
2348
if not inplace :
2271
2349
return idx
@@ -2280,27 +2358,42 @@ def set_levels(self, levels, inplace=False, verify_integrity=True):
2280
2358
def _get_labels (self ):
2281
2359
return self ._labels
2282
2360
2283
- def _set_labels (self , labels , copy = False , validate = True ,
2361
+ def _set_labels (self , labels , level = None , copy = False , validate = True ,
2284
2362
verify_integrity = False ):
2285
- if validate and len (labels ) != self .nlevels :
2286
- raise ValueError ("Length of labels must match length of levels" )
2287
- self ._labels = FrozenList (
2288
- _ensure_frozen (labs , copy = copy )._shallow_copy () for labs in labels )
2363
+
2364
+ if validate and level is None and len (labels ) != self .nlevels :
2365
+ raise ValueError ("Length of labels must match number of levels" )
2366
+ if validate and level is not None and len (labels ) != len (level ):
2367
+ raise ValueError ('Length of labels must match length of levels.' )
2368
+
2369
+ if level is None :
2370
+ new_labels = FrozenList (_ensure_frozen (v , copy = copy )._shallow_copy ()
2371
+ for v in labels )
2372
+ else :
2373
+ level = [self ._get_level_number (l ) for l in level ]
2374
+ new_labels = list (self ._labels )
2375
+ for l , v in zip (level , labels ):
2376
+ new_labels [l ] = _ensure_frozen (v , copy = copy )._shallow_copy ()
2377
+ new_labels = FrozenList (new_labels )
2378
+
2379
+ self ._labels = new_labels
2289
2380
self ._tuples = None
2290
2381
self ._reset_cache ()
2291
2382
2292
2383
if verify_integrity :
2293
2384
self ._verify_integrity ()
2294
2385
2295
- def set_labels (self , labels , inplace = False , verify_integrity = True ):
2386
+ def set_labels (self , labels , level = None , inplace = False , verify_integrity = True ):
2296
2387
"""
2297
2388
Set new labels on MultiIndex. Defaults to returning
2298
2389
new index.
2299
2390
2300
2391
Parameters
2301
2392
----------
2302
- labels : sequence of arrays
2393
+ labels : sequence or list of sequence
2303
2394
new labels to apply
2395
+ level : int or level name, or sequence of int / level names (default None)
2396
+ level(s) to set (None for all levels)
2304
2397
inplace : bool
2305
2398
if True, mutates in place
2306
2399
verify_integrity : bool (default True)
@@ -2309,15 +2402,46 @@ def set_labels(self, labels, inplace=False, verify_integrity=True):
2309
2402
Returns
2310
2403
-------
2311
2404
new index (of same type and class...etc)
2312
- """
2313
- if not com .is_list_like (labels ) or not com .is_list_like (labels [0 ]):
2314
- raise TypeError ("Labels must be list of lists-like" )
2405
+
2406
+ Examples
2407
+ --------
2408
+ >>> idx = MultiIndex.from_tuples([(1, u'one'), (1, u'two'),
2409
+ (2, u'one'), (2, u'two')],
2410
+ names=['foo', 'bar'])
2411
+ >>> idx.set_labels([[1,0,1,0], [0,0,1,1]])
2412
+ MultiIndex(levels=[[1, 2], [u'one', u'two']],
2413
+ labels=[[1, 0, 1, 0], [0, 0, 1, 1]],
2414
+ names=[u'foo', u'bar'])
2415
+ >>> idx.set_labels([1,0,1,0], level=0)
2416
+ MultiIndex(levels=[[1, 2], [u'one', u'two']],
2417
+ labels=[[1, 0, 1, 0], [0, 1, 0, 1]],
2418
+ names=[u'foo', u'bar'])
2419
+ >>> idx.set_labels([0,0,1,1], level='bar')
2420
+ MultiIndex(levels=[[1, 2], [u'one', u'two']],
2421
+ labels=[[0, 0, 1, 1], [0, 0, 1, 1]],
2422
+ names=[u'foo', u'bar'])
2423
+ >>> idx.set_labels([[1,0,1,0], [0,0,1,1]], level=[0,1])
2424
+ MultiIndex(levels=[[1, 2], [u'one', u'two']],
2425
+ labels=[[1, 0, 1, 0], [0, 0, 1, 1]],
2426
+ names=[u'foo', u'bar'])
2427
+ """
2428
+ if level is not None and not com .is_list_like (level ):
2429
+ if not com .is_list_like (labels ):
2430
+ raise TypeError ("Labels must be list-like" )
2431
+ if com .is_list_like (labels [0 ]):
2432
+ raise TypeError ("Labels must be list-like" )
2433
+ level = [level ]
2434
+ labels = [labels ]
2435
+ elif level is None or com .is_list_like (level ):
2436
+ if not com .is_list_like (labels ) or not com .is_list_like (labels [0 ]):
2437
+ raise TypeError ("Labels must be list of lists-like" )
2438
+
2315
2439
if inplace :
2316
2440
idx = self
2317
2441
else :
2318
2442
idx = self ._shallow_copy ()
2319
2443
idx ._reset_identity ()
2320
- idx ._set_labels (labels , verify_integrity = verify_integrity )
2444
+ idx ._set_labels (labels , level = level , verify_integrity = verify_integrity )
2321
2445
if not inplace :
2322
2446
return idx
2323
2447
@@ -2434,18 +2558,30 @@ def __len__(self):
2434
2558
def _get_names (self ):
2435
2559
return FrozenList (level .name for level in self .levels )
2436
2560
2437
- def _set_names (self , values , validate = True ):
2561
+ def _set_names (self , names , level = None , validate = True ):
2438
2562
"""
2439
2563
sets names on levels. WARNING: mutates!
2440
2564
2441
2565
Note that you generally want to set this *after* changing levels, so
2442
- that it only acts on copies"""
2443
- values = list (values )
2444
- if validate and len (values ) != self .nlevels :
2445
- raise ValueError ('Length of names must match length of levels' )
2566
+ that it only acts on copies
2567
+ """
2568
+
2569
+ names = list (names )
2570
+
2571
+ if validate and level is not None and len (names ) != len (level ):
2572
+ raise ValueError ('Length of names must match length of level.' )
2573
+ if validate and level is None and len (names ) != self .nlevels :
2574
+ raise ValueError (
2575
+ 'Length of names must match number of levels in MultiIndex.' )
2576
+
2577
+ if level is None :
2578
+ level = range (self .nlevels )
2579
+ else :
2580
+ level = [self ._get_level_number (l ) for l in level ]
2581
+
2446
2582
# set the name
2447
- for name , level in zip (values , self . levels ):
2448
- level .rename (name , inplace = True )
2583
+ for l , name in zip (level , names ):
2584
+ self . levels [ l ] .rename (name , inplace = True )
2449
2585
2450
2586
names = property (
2451
2587
fset = _set_names , fget = _get_names , doc = "Names of levels in MultiIndex" )
0 commit comments