test_constructor.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. # -*- coding: utf-8 -*-
  2. from collections import OrderedDict
  3. import re
  4. import numpy as np
  5. import pytest
  6. from pandas._libs.tslib import Timestamp
  7. from pandas.compat import lrange, range
  8. from pandas.core.dtypes.cast import construct_1d_object_array_from_listlike
  9. import pandas as pd
  10. from pandas import Index, MultiIndex, date_range
  11. import pandas.util.testing as tm
  12. def test_constructor_single_level():
  13. result = MultiIndex(levels=[['foo', 'bar', 'baz', 'qux']],
  14. codes=[[0, 1, 2, 3]], names=['first'])
  15. assert isinstance(result, MultiIndex)
  16. expected = Index(['foo', 'bar', 'baz', 'qux'], name='first')
  17. tm.assert_index_equal(result.levels[0], expected)
  18. assert result.names == ['first']
  19. def test_constructor_no_levels():
  20. msg = "non-zero number of levels/codes"
  21. with pytest.raises(ValueError, match=msg):
  22. MultiIndex(levels=[], codes=[])
  23. both_re = re.compile('Must pass both levels and codes')
  24. with pytest.raises(TypeError, match=both_re):
  25. MultiIndex(levels=[])
  26. with pytest.raises(TypeError, match=both_re):
  27. MultiIndex(codes=[])
  28. def test_constructor_nonhashable_names():
  29. # GH 20527
  30. levels = [[1, 2], [u'one', u'two']]
  31. codes = [[0, 0, 1, 1], [0, 1, 0, 1]]
  32. names = (['foo'], ['bar'])
  33. message = "MultiIndex.name must be a hashable type"
  34. with pytest.raises(TypeError, match=message):
  35. MultiIndex(levels=levels, codes=codes, names=names)
  36. # With .rename()
  37. mi = MultiIndex(levels=[[1, 2], [u'one', u'two']],
  38. codes=[[0, 0, 1, 1], [0, 1, 0, 1]],
  39. names=('foo', 'bar'))
  40. renamed = [['foor'], ['barr']]
  41. with pytest.raises(TypeError, match=message):
  42. mi.rename(names=renamed)
  43. # With .set_names()
  44. with pytest.raises(TypeError, match=message):
  45. mi.set_names(names=renamed)
  46. def test_constructor_mismatched_codes_levels(idx):
  47. codes = [np.array([1]), np.array([2]), np.array([3])]
  48. levels = ["a"]
  49. msg = "Length of levels and codes must be the same"
  50. with pytest.raises(ValueError, match=msg):
  51. MultiIndex(levels=levels, codes=codes)
  52. length_error = re.compile('>= length of level')
  53. label_error = re.compile(r'Unequal code lengths: \[4, 2\]')
  54. # important to check that it's looking at the right thing.
  55. with pytest.raises(ValueError, match=length_error):
  56. MultiIndex(levels=[['a'], ['b']],
  57. codes=[[0, 1, 2, 3], [0, 3, 4, 1]])
  58. with pytest.raises(ValueError, match=label_error):
  59. MultiIndex(levels=[['a'], ['b']], codes=[[0, 0, 0, 0], [0, 0]])
  60. # external API
  61. with pytest.raises(ValueError, match=length_error):
  62. idx.copy().set_levels([['a'], ['b']])
  63. with pytest.raises(ValueError, match=label_error):
  64. idx.copy().set_codes([[0, 0, 0, 0], [0, 0]])
  65. def test_labels_deprecated(idx):
  66. # GH23752
  67. with tm.assert_produces_warning(FutureWarning):
  68. MultiIndex(levels=[['foo', 'bar', 'baz', 'qux']],
  69. labels=[[0, 1, 2, 3]], names=['first'])
  70. with tm.assert_produces_warning(FutureWarning):
  71. idx.labels
  72. def test_copy_in_constructor():
  73. levels = np.array(["a", "b", "c"])
  74. codes = np.array([1, 1, 2, 0, 0, 1, 1])
  75. val = codes[0]
  76. mi = MultiIndex(levels=[levels, levels], codes=[codes, codes],
  77. copy=True)
  78. assert mi.codes[0][0] == val
  79. codes[0] = 15
  80. assert mi.codes[0][0] == val
  81. val = levels[0]
  82. levels[0] = "PANDA"
  83. assert mi.levels[0][0] == val
  84. # ----------------------------------------------------------------------------
  85. # from_arrays
  86. # ----------------------------------------------------------------------------
  87. def test_from_arrays(idx):
  88. arrays = [np.asarray(lev).take(level_codes)
  89. for lev, level_codes in zip(idx.levels, idx.codes)]
  90. # list of arrays as input
  91. result = MultiIndex.from_arrays(arrays, names=idx.names)
  92. tm.assert_index_equal(result, idx)
  93. # infer correctly
  94. result = MultiIndex.from_arrays([[pd.NaT, Timestamp('20130101')],
  95. ['a', 'b']])
  96. assert result.levels[0].equals(Index([Timestamp('20130101')]))
  97. assert result.levels[1].equals(Index(['a', 'b']))
  98. def test_from_arrays_iterator(idx):
  99. # GH 18434
  100. arrays = [np.asarray(lev).take(level_codes)
  101. for lev, level_codes in zip(idx.levels, idx.codes)]
  102. # iterator as input
  103. result = MultiIndex.from_arrays(iter(arrays), names=idx.names)
  104. tm.assert_index_equal(result, idx)
  105. # invalid iterator input
  106. msg = "Input must be a list / sequence of array-likes."
  107. with pytest.raises(TypeError, match=msg):
  108. MultiIndex.from_arrays(0)
  109. def test_from_arrays_index_series_datetimetz():
  110. idx1 = pd.date_range('2015-01-01 10:00', freq='D', periods=3,
  111. tz='US/Eastern')
  112. idx2 = pd.date_range('2015-01-01 10:00', freq='H', periods=3,
  113. tz='Asia/Tokyo')
  114. result = pd.MultiIndex.from_arrays([idx1, idx2])
  115. tm.assert_index_equal(result.get_level_values(0), idx1)
  116. tm.assert_index_equal(result.get_level_values(1), idx2)
  117. result2 = pd.MultiIndex.from_arrays([pd.Series(idx1), pd.Series(idx2)])
  118. tm.assert_index_equal(result2.get_level_values(0), idx1)
  119. tm.assert_index_equal(result2.get_level_values(1), idx2)
  120. tm.assert_index_equal(result, result2)
  121. def test_from_arrays_index_series_timedelta():
  122. idx1 = pd.timedelta_range('1 days', freq='D', periods=3)
  123. idx2 = pd.timedelta_range('2 hours', freq='H', periods=3)
  124. result = pd.MultiIndex.from_arrays([idx1, idx2])
  125. tm.assert_index_equal(result.get_level_values(0), idx1)
  126. tm.assert_index_equal(result.get_level_values(1), idx2)
  127. result2 = pd.MultiIndex.from_arrays([pd.Series(idx1), pd.Series(idx2)])
  128. tm.assert_index_equal(result2.get_level_values(0), idx1)
  129. tm.assert_index_equal(result2.get_level_values(1), idx2)
  130. tm.assert_index_equal(result, result2)
  131. def test_from_arrays_index_series_period():
  132. idx1 = pd.period_range('2011-01-01', freq='D', periods=3)
  133. idx2 = pd.period_range('2015-01-01', freq='H', periods=3)
  134. result = pd.MultiIndex.from_arrays([idx1, idx2])
  135. tm.assert_index_equal(result.get_level_values(0), idx1)
  136. tm.assert_index_equal(result.get_level_values(1), idx2)
  137. result2 = pd.MultiIndex.from_arrays([pd.Series(idx1), pd.Series(idx2)])
  138. tm.assert_index_equal(result2.get_level_values(0), idx1)
  139. tm.assert_index_equal(result2.get_level_values(1), idx2)
  140. tm.assert_index_equal(result, result2)
  141. def test_from_arrays_index_datetimelike_mixed():
  142. idx1 = pd.date_range('2015-01-01 10:00', freq='D', periods=3,
  143. tz='US/Eastern')
  144. idx2 = pd.date_range('2015-01-01 10:00', freq='H', periods=3)
  145. idx3 = pd.timedelta_range('1 days', freq='D', periods=3)
  146. idx4 = pd.period_range('2011-01-01', freq='D', periods=3)
  147. result = pd.MultiIndex.from_arrays([idx1, idx2, idx3, idx4])
  148. tm.assert_index_equal(result.get_level_values(0), idx1)
  149. tm.assert_index_equal(result.get_level_values(1), idx2)
  150. tm.assert_index_equal(result.get_level_values(2), idx3)
  151. tm.assert_index_equal(result.get_level_values(3), idx4)
  152. result2 = pd.MultiIndex.from_arrays([pd.Series(idx1),
  153. pd.Series(idx2),
  154. pd.Series(idx3),
  155. pd.Series(idx4)])
  156. tm.assert_index_equal(result2.get_level_values(0), idx1)
  157. tm.assert_index_equal(result2.get_level_values(1), idx2)
  158. tm.assert_index_equal(result2.get_level_values(2), idx3)
  159. tm.assert_index_equal(result2.get_level_values(3), idx4)
  160. tm.assert_index_equal(result, result2)
  161. def test_from_arrays_index_series_categorical():
  162. # GH13743
  163. idx1 = pd.CategoricalIndex(list("abcaab"), categories=list("bac"),
  164. ordered=False)
  165. idx2 = pd.CategoricalIndex(list("abcaab"), categories=list("bac"),
  166. ordered=True)
  167. result = pd.MultiIndex.from_arrays([idx1, idx2])
  168. tm.assert_index_equal(result.get_level_values(0), idx1)
  169. tm.assert_index_equal(result.get_level_values(1), idx2)
  170. result2 = pd.MultiIndex.from_arrays([pd.Series(idx1), pd.Series(idx2)])
  171. tm.assert_index_equal(result2.get_level_values(0), idx1)
  172. tm.assert_index_equal(result2.get_level_values(1), idx2)
  173. result3 = pd.MultiIndex.from_arrays([idx1.values, idx2.values])
  174. tm.assert_index_equal(result3.get_level_values(0), idx1)
  175. tm.assert_index_equal(result3.get_level_values(1), idx2)
  176. def test_from_arrays_empty():
  177. # 0 levels
  178. msg = "Must pass non-zero number of levels/codes"
  179. with pytest.raises(ValueError, match=msg):
  180. MultiIndex.from_arrays(arrays=[])
  181. # 1 level
  182. result = MultiIndex.from_arrays(arrays=[[]], names=['A'])
  183. assert isinstance(result, MultiIndex)
  184. expected = Index([], name='A')
  185. tm.assert_index_equal(result.levels[0], expected)
  186. # N levels
  187. for N in [2, 3]:
  188. arrays = [[]] * N
  189. names = list('ABC')[:N]
  190. result = MultiIndex.from_arrays(arrays=arrays, names=names)
  191. expected = MultiIndex(levels=[[]] * N, codes=[[]] * N,
  192. names=names)
  193. tm.assert_index_equal(result, expected)
  194. @pytest.mark.parametrize('invalid_array', [
  195. (1),
  196. ([1]),
  197. ([1, 2]),
  198. ([[1], 2]),
  199. ('a'),
  200. (['a']),
  201. (['a', 'b']),
  202. ([['a'], 'b']),
  203. ])
  204. def test_from_arrays_invalid_input(invalid_array):
  205. invalid_inputs = [1, [1], [1, 2], [[1], 2],
  206. 'a', ['a'], ['a', 'b'], [['a'], 'b']]
  207. for i in invalid_inputs:
  208. pytest.raises(TypeError, MultiIndex.from_arrays, arrays=i)
  209. @pytest.mark.parametrize('idx1, idx2', [
  210. ([1, 2, 3], ['a', 'b']),
  211. ([], ['a', 'b']),
  212. ([1, 2, 3], [])
  213. ])
  214. def test_from_arrays_different_lengths(idx1, idx2):
  215. # see gh-13599
  216. msg = '^all arrays must be same length$'
  217. with pytest.raises(ValueError, match=msg):
  218. MultiIndex.from_arrays([idx1, idx2])
  219. # ----------------------------------------------------------------------------
  220. # from_tuples
  221. # ----------------------------------------------------------------------------
  222. def test_from_tuples():
  223. msg = 'Cannot infer number of levels from empty list'
  224. with pytest.raises(TypeError, match=msg):
  225. MultiIndex.from_tuples([])
  226. expected = MultiIndex(levels=[[1, 3], [2, 4]],
  227. codes=[[0, 1], [0, 1]],
  228. names=['a', 'b'])
  229. # input tuples
  230. result = MultiIndex.from_tuples(((1, 2), (3, 4)), names=['a', 'b'])
  231. tm.assert_index_equal(result, expected)
  232. def test_from_tuples_iterator():
  233. # GH 18434
  234. # input iterator for tuples
  235. expected = MultiIndex(levels=[[1, 3], [2, 4]],
  236. codes=[[0, 1], [0, 1]],
  237. names=['a', 'b'])
  238. result = MultiIndex.from_tuples(zip([1, 3], [2, 4]), names=['a', 'b'])
  239. tm.assert_index_equal(result, expected)
  240. # input non-iterables
  241. msg = 'Input must be a list / sequence of tuple-likes.'
  242. with pytest.raises(TypeError, match=msg):
  243. MultiIndex.from_tuples(0)
  244. def test_from_tuples_empty():
  245. # GH 16777
  246. result = MultiIndex.from_tuples([], names=['a', 'b'])
  247. expected = MultiIndex.from_arrays(arrays=[[], []],
  248. names=['a', 'b'])
  249. tm.assert_index_equal(result, expected)
  250. def test_from_tuples_index_values(idx):
  251. result = MultiIndex.from_tuples(idx)
  252. assert (result.values == idx.values).all()
  253. def test_tuples_with_name_string():
  254. # GH 15110 and GH 14848
  255. li = [(0, 0, 1), (0, 1, 0), (1, 0, 0)]
  256. with pytest.raises(ValueError):
  257. pd.Index(li, name='abc')
  258. with pytest.raises(ValueError):
  259. pd.Index(li, name='a')
  260. def test_from_tuples_with_tuple_label():
  261. # GH 15457
  262. expected = pd.DataFrame([[2, 1, 2], [4, (1, 2), 3]],
  263. columns=['a', 'b', 'c']).set_index(['a', 'b'])
  264. idx = pd.MultiIndex.from_tuples([(2, 1), (4, (1, 2))], names=('a', 'b'))
  265. result = pd.DataFrame([2, 3], columns=['c'], index=idx)
  266. tm.assert_frame_equal(expected, result)
  267. # ----------------------------------------------------------------------------
  268. # from_product
  269. # ----------------------------------------------------------------------------
  270. def test_from_product_empty_zero_levels():
  271. # 0 levels
  272. msg = "Must pass non-zero number of levels/codes"
  273. with pytest.raises(ValueError, match=msg):
  274. MultiIndex.from_product([])
  275. def test_from_product_empty_one_level():
  276. result = MultiIndex.from_product([[]], names=['A'])
  277. expected = pd.Index([], name='A')
  278. tm.assert_index_equal(result.levels[0], expected)
  279. @pytest.mark.parametrize('first, second', [
  280. ([], []),
  281. (['foo', 'bar', 'baz'], []),
  282. ([], ['a', 'b', 'c']),
  283. ])
  284. def test_from_product_empty_two_levels(first, second):
  285. names = ['A', 'B']
  286. result = MultiIndex.from_product([first, second], names=names)
  287. expected = MultiIndex(levels=[first, second],
  288. codes=[[], []], names=names)
  289. tm.assert_index_equal(result, expected)
  290. @pytest.mark.parametrize('N', list(range(4)))
  291. def test_from_product_empty_three_levels(N):
  292. # GH12258
  293. names = ['A', 'B', 'C']
  294. lvl2 = lrange(N)
  295. result = MultiIndex.from_product([[], lvl2, []], names=names)
  296. expected = MultiIndex(levels=[[], lvl2, []],
  297. codes=[[], [], []], names=names)
  298. tm.assert_index_equal(result, expected)
  299. @pytest.mark.parametrize('invalid_input', [
  300. 1,
  301. [1],
  302. [1, 2],
  303. [[1], 2],
  304. 'a',
  305. ['a'],
  306. ['a', 'b'],
  307. [['a'], 'b'],
  308. ])
  309. def test_from_product_invalid_input(invalid_input):
  310. pytest.raises(TypeError, MultiIndex.from_product, iterables=invalid_input)
  311. def test_from_product_datetimeindex():
  312. dt_index = date_range('2000-01-01', periods=2)
  313. mi = pd.MultiIndex.from_product([[1, 2], dt_index])
  314. etalon = construct_1d_object_array_from_listlike([
  315. (1, pd.Timestamp('2000-01-01')),
  316. (1, pd.Timestamp('2000-01-02')),
  317. (2, pd.Timestamp('2000-01-01')),
  318. (2, pd.Timestamp('2000-01-02')),
  319. ])
  320. tm.assert_numpy_array_equal(mi.values, etalon)
  321. @pytest.mark.parametrize('ordered', [False, True])
  322. @pytest.mark.parametrize('f', [
  323. lambda x: x,
  324. lambda x: pd.Series(x),
  325. lambda x: x.values
  326. ])
  327. def test_from_product_index_series_categorical(ordered, f):
  328. # GH13743
  329. first = ['foo', 'bar']
  330. idx = pd.CategoricalIndex(list("abcaab"), categories=list("bac"),
  331. ordered=ordered)
  332. expected = pd.CategoricalIndex(list("abcaab") + list("abcaab"),
  333. categories=list("bac"),
  334. ordered=ordered)
  335. result = pd.MultiIndex.from_product([first, f(idx)])
  336. tm.assert_index_equal(result.get_level_values(1), expected)
  337. def test_from_product():
  338. first = ['foo', 'bar', 'buz']
  339. second = ['a', 'b', 'c']
  340. names = ['first', 'second']
  341. result = MultiIndex.from_product([first, second], names=names)
  342. tuples = [('foo', 'a'), ('foo', 'b'), ('foo', 'c'), ('bar', 'a'),
  343. ('bar', 'b'), ('bar', 'c'), ('buz', 'a'), ('buz', 'b'),
  344. ('buz', 'c')]
  345. expected = MultiIndex.from_tuples(tuples, names=names)
  346. tm.assert_index_equal(result, expected)
  347. def test_from_product_iterator():
  348. # GH 18434
  349. first = ['foo', 'bar', 'buz']
  350. second = ['a', 'b', 'c']
  351. names = ['first', 'second']
  352. tuples = [('foo', 'a'), ('foo', 'b'), ('foo', 'c'), ('bar', 'a'),
  353. ('bar', 'b'), ('bar', 'c'), ('buz', 'a'), ('buz', 'b'),
  354. ('buz', 'c')]
  355. expected = MultiIndex.from_tuples(tuples, names=names)
  356. # iterator as input
  357. result = MultiIndex.from_product(iter([first, second]), names=names)
  358. tm.assert_index_equal(result, expected)
  359. # Invalid non-iterable input
  360. msg = "Input must be a list / sequence of iterables."
  361. with pytest.raises(TypeError, match=msg):
  362. MultiIndex.from_product(0)
  363. def test_create_index_existing_name(idx):
  364. # GH11193, when an existing index is passed, and a new name is not
  365. # specified, the new index should inherit the previous object name
  366. index = idx
  367. index.names = ['foo', 'bar']
  368. result = pd.Index(index)
  369. expected = Index(
  370. Index([
  371. ('foo', 'one'), ('foo', 'two'),
  372. ('bar', 'one'), ('baz', 'two'),
  373. ('qux', 'one'), ('qux', 'two')],
  374. dtype='object'
  375. ),
  376. names=['foo', 'bar']
  377. )
  378. tm.assert_index_equal(result, expected)
  379. result = pd.Index(index, names=['A', 'B'])
  380. expected = Index(
  381. Index([
  382. ('foo', 'one'), ('foo', 'two'),
  383. ('bar', 'one'), ('baz', 'two'),
  384. ('qux', 'one'), ('qux', 'two')],
  385. dtype='object'
  386. ),
  387. names=['A', 'B']
  388. )
  389. tm.assert_index_equal(result, expected)
  390. # ----------------------------------------------------------------------------
  391. # from_frame
  392. # ----------------------------------------------------------------------------
  393. def test_from_frame():
  394. # GH 22420
  395. df = pd.DataFrame([['a', 'a'], ['a', 'b'], ['b', 'a'], ['b', 'b']],
  396. columns=['L1', 'L2'])
  397. expected = pd.MultiIndex.from_tuples([('a', 'a'), ('a', 'b'),
  398. ('b', 'a'), ('b', 'b')],
  399. names=['L1', 'L2'])
  400. result = pd.MultiIndex.from_frame(df)
  401. tm.assert_index_equal(expected, result)
  402. @pytest.mark.parametrize('non_frame', [
  403. pd.Series([1, 2, 3, 4]),
  404. [1, 2, 3, 4],
  405. [[1, 2], [3, 4], [5, 6]],
  406. pd.Index([1, 2, 3, 4]),
  407. np.array([[1, 2], [3, 4], [5, 6]]),
  408. 27
  409. ])
  410. def test_from_frame_error(non_frame):
  411. # GH 22420
  412. with pytest.raises(TypeError, match='Input must be a DataFrame'):
  413. pd.MultiIndex.from_frame(non_frame)
  414. def test_from_frame_dtype_fidelity():
  415. # GH 22420
  416. df = pd.DataFrame(OrderedDict([
  417. ('dates', pd.date_range('19910905', periods=6, tz='US/Eastern')),
  418. ('a', [1, 1, 1, 2, 2, 2]),
  419. ('b', pd.Categorical(['a', 'a', 'b', 'b', 'c', 'c'], ordered=True)),
  420. ('c', ['x', 'x', 'y', 'z', 'x', 'y'])
  421. ]))
  422. original_dtypes = df.dtypes.to_dict()
  423. expected_mi = pd.MultiIndex.from_arrays([
  424. pd.date_range('19910905', periods=6, tz='US/Eastern'),
  425. [1, 1, 1, 2, 2, 2],
  426. pd.Categorical(['a', 'a', 'b', 'b', 'c', 'c'], ordered=True),
  427. ['x', 'x', 'y', 'z', 'x', 'y']
  428. ], names=['dates', 'a', 'b', 'c'])
  429. mi = pd.MultiIndex.from_frame(df)
  430. mi_dtypes = {name: mi.levels[i].dtype for i, name in enumerate(mi.names)}
  431. tm.assert_index_equal(expected_mi, mi)
  432. assert original_dtypes == mi_dtypes
  433. @pytest.mark.parametrize('names_in,names_out', [
  434. (None, [('L1', 'x'), ('L2', 'y')]),
  435. (['x', 'y'], ['x', 'y']),
  436. ])
  437. def test_from_frame_valid_names(names_in, names_out):
  438. # GH 22420
  439. df = pd.DataFrame([['a', 'a'], ['a', 'b'], ['b', 'a'], ['b', 'b']],
  440. columns=pd.MultiIndex.from_tuples([('L1', 'x'),
  441. ('L2', 'y')]))
  442. mi = pd.MultiIndex.from_frame(df, names=names_in)
  443. assert mi.names == names_out
  444. @pytest.mark.parametrize('names_in,names_out', [
  445. ('bad_input', ValueError("Names should be list-like for a MultiIndex")),
  446. (['a', 'b', 'c'], ValueError("Length of names must match number of "
  447. "levels in MultiIndex."))
  448. ])
  449. def test_from_frame_invalid_names(names_in, names_out):
  450. # GH 22420
  451. df = pd.DataFrame([['a', 'a'], ['a', 'b'], ['b', 'a'], ['b', 'b']],
  452. columns=pd.MultiIndex.from_tuples([('L1', 'x'),
  453. ('L2', 'y')]))
  454. with pytest.raises(type(names_out), match=names_out.args[0]):
  455. pd.MultiIndex.from_frame(df, names=names_in)