@@ -362,36 +362,69 @@ def nlevels(self):
362362 def _get_names (self ):
363363 return FrozenList ((self .name ,))
364364
365- def _set_names (self , values ):
365+ def _set_names (self , values , level = None ):
366366 if len (values ) != 1 :
367367 raise ValueError ('Length of new names must be 1, got %d'
368368 % len (values ))
369369 self .name = values [0 ]
370370
371371 names = property (fset = _set_names , fget = _get_names )
372372
373- def set_names (self , names , inplace = False ):
373+ def set_names (self , names , level = None , inplace = False ):
374374 """
375375 Set new names on index. Defaults to returning new index.
376376
377377 Parameters
378378 ----------
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
381384 inplace : bool
382385 if True, mutates in place
383386
384387 Returns
385388 -------
386389 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'])
387408 """
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 :
389416 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+
390423 if inplace :
391424 idx = self
392425 else :
393426 idx = self ._shallow_copy ()
394- idx ._set_names (names )
427+ idx ._set_names (names , level = level )
395428 if not inplace :
396429 return idx
397430
@@ -2218,19 +2251,30 @@ def _verify_integrity(self):
22182251 def _get_levels (self ):
22192252 return self ._levels
22202253
2221- def _set_levels (self , levels , copy = False , validate = True ,
2254+ def _set_levels (self , levels , level = None , copy = False , validate = True ,
22222255 verify_integrity = False ):
22232256 # This is NOT part of the levels property because it should be
22242257 # externally not allowed to set levels. User beware if you change
22252258 # _levels directly
22262259 if validate and len (levels ) == 0 :
22272260 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+
22322276 names = self .names
2233- self ._levels = levels
2277+ self ._levels = new_levels
22342278 if any (names ):
22352279 self ._set_names (names )
22362280
@@ -2240,15 +2284,17 @@ def _set_levels(self, levels, copy=False, validate=True,
22402284 if verify_integrity :
22412285 self ._verify_integrity ()
22422286
2243- def set_levels (self , levels , inplace = False , verify_integrity = True ):
2287+ def set_levels (self , levels , level = None , inplace = False , verify_integrity = True ):
22442288 """
22452289 Set new levels on MultiIndex. Defaults to returning
22462290 new index.
22472291
22482292 Parameters
22492293 ----------
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)
22522298 inplace : bool
22532299 if True, mutates in place
22542300 verify_integrity : bool (default True)
@@ -2257,15 +2303,47 @@ def set_levels(self, levels, inplace=False, verify_integrity=True):
22572303 Returns
22582304 -------
22592305 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+
22632341 if inplace :
22642342 idx = self
22652343 else :
22662344 idx = self ._shallow_copy ()
22672345 idx ._reset_identity ()
2268- idx ._set_levels (levels , validate = True ,
2346+ idx ._set_levels (levels , level = level , validate = True ,
22692347 verify_integrity = verify_integrity )
22702348 if not inplace :
22712349 return idx
@@ -2280,27 +2358,42 @@ def set_levels(self, levels, inplace=False, verify_integrity=True):
22802358 def _get_labels (self ):
22812359 return self ._labels
22822360
2283- def _set_labels (self , labels , copy = False , validate = True ,
2361+ def _set_labels (self , labels , level = None , copy = False , validate = True ,
22842362 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
22892380 self ._tuples = None
22902381 self ._reset_cache ()
22912382
22922383 if verify_integrity :
22932384 self ._verify_integrity ()
22942385
2295- def set_labels (self , labels , inplace = False , verify_integrity = True ):
2386+ def set_labels (self , labels , level = None , inplace = False , verify_integrity = True ):
22962387 """
22972388 Set new labels on MultiIndex. Defaults to returning
22982389 new index.
22992390
23002391 Parameters
23012392 ----------
2302- labels : sequence of arrays
2393+ labels : sequence or list of sequence
23032394 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)
23042397 inplace : bool
23052398 if True, mutates in place
23062399 verify_integrity : bool (default True)
@@ -2309,15 +2402,46 @@ def set_labels(self, labels, inplace=False, verify_integrity=True):
23092402 Returns
23102403 -------
23112404 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+
23152439 if inplace :
23162440 idx = self
23172441 else :
23182442 idx = self ._shallow_copy ()
23192443 idx ._reset_identity ()
2320- idx ._set_labels (labels , verify_integrity = verify_integrity )
2444+ idx ._set_labels (labels , level = level , verify_integrity = verify_integrity )
23212445 if not inplace :
23222446 return idx
23232447
@@ -2434,18 +2558,30 @@ def __len__(self):
24342558 def _get_names (self ):
24352559 return FrozenList (level .name for level in self .levels )
24362560
2437- def _set_names (self , values , validate = True ):
2561+ def _set_names (self , names , level = None , validate = True ):
24382562 """
24392563 sets names on levels. WARNING: mutates!
24402564
24412565 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+
24462582 # 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 )
24492585
24502586 names = property (
24512587 fset = _set_names , fget = _get_names , doc = "Names of levels in MultiIndex" )
0 commit comments