diff --git a/doc/source/whatsnew/v0.19.1.txt b/doc/source/whatsnew/v0.19.1.txt index 3edb8c1fa9071..01e9d2ff4ce7f 100644 --- a/doc/source/whatsnew/v0.19.1.txt +++ b/doc/source/whatsnew/v0.19.1.txt @@ -44,4 +44,5 @@ Bug Fixes - Bug in ``pd.concat`` where names of the ``keys`` were not propagated to the resulting ``MultiIndex`` (:issue:`14252`) +- Bug in ``pd.concat`` where ``axis`` cannot take string parameters ``'rows'`` or ``'columns'`` (:issue:`14369`) - Bug in ``MultiIndex.set_levels`` where illegal level values were still set after raising an error (:issue:`13754`) diff --git a/pandas/tests/frame/test_combine_concat.py b/pandas/tests/frame/test_combine_concat.py index b7cd8a1c01224..81aa694577fb5 100644 --- a/pandas/tests/frame/test_combine_concat.py +++ b/pandas/tests/frame/test_combine_concat.py @@ -347,6 +347,65 @@ def test_concat_named_keys(self): names=[None, None])) assert_frame_equal(concatted_unnamed, expected_unnamed) + def test_concat_axis_parameter(self): + # GH 14369 + df1 = pd.DataFrame({'A': [0.1, 0.2]}, index=range(2)) + df2 = pd.DataFrame({'A': [0.3, 0.4]}, index=range(2)) + + # Index/row/0 DataFrame + expected_index = pd.DataFrame( + {'A': [0.1, 0.2, 0.3, 0.4]}, index=[0, 1, 0, 1]) + + concatted_index = pd.concat([df1, df2], axis='index') + assert_frame_equal(concatted_index, expected_index) + + concatted_row = pd.concat([df1, df2], axis='rows') + assert_frame_equal(concatted_row, expected_index) + + concatted_0 = pd.concat([df1, df2], axis=0) + assert_frame_equal(concatted_0, expected_index) + + # Columns/1 DataFrame + expected_columns = pd.DataFrame( + [[0.1, 0.3], [0.2, 0.4]], index=[0, 1], columns=['A', 'A']) + + concatted_columns = pd.concat([df1, df2], axis='columns') + assert_frame_equal(concatted_columns, expected_columns) + + concatted_1 = pd.concat([df1, df2], axis=1) + assert_frame_equal(concatted_1, expected_columns) + + series1 = pd.Series([0.1, 0.2]) + series2 = pd.Series([0.3, 0.4]) + + # Index/row/0 Series + expected_index_series = pd.Series( + [0.1, 0.2, 0.3, 0.4], index=[0, 1, 0, 1]) + + concatted_index_series = pd.concat([series1, series2], axis='index') + assert_series_equal(concatted_index_series, expected_index_series) + + concatted_row_series = pd.concat([series1, series2], axis='rows') + assert_series_equal(concatted_row_series, expected_index_series) + + concatted_0_series = pd.concat([series1, series2], axis=0) + assert_series_equal(concatted_0_series, expected_index_series) + + # Columns/1 Series + expected_columns_series = pd.DataFrame( + [[0.1, 0.3], [0.2, 0.4]], index=[0, 1], columns=[0, 1]) + + concatted_columns_series = pd.concat( + [series1, series2], axis='columns') + assert_frame_equal(concatted_columns_series, expected_columns_series) + + concatted_1_series = pd.concat([series1, series2], axis=1) + assert_frame_equal(concatted_1_series, expected_columns_series) + + # Testing ValueError + with assertRaisesRegexp(ValueError, 'No axis named'): + pd.concat([series1, series2], axis='something') + class TestDataFrameCombineFirst(tm.TestCase, TestData): diff --git a/pandas/tools/merge.py b/pandas/tools/merge.py index a8c43195f5552..ce7f8908d7506 100644 --- a/pandas/tools/merge.py +++ b/pandas/tools/merge.py @@ -1283,7 +1283,7 @@ def concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False, argument, unless it is passed, in which case the values will be selected (see below). Any None objects will be dropped silently unless they are all None in which case a ValueError will be raised - axis : {0, 1, ...}, default 0 + axis : {0/'index', 1/'columns'}, default 0 The axis to concatenate along join : {'inner', 'outer'}, default 'outer' How to handle indexes on other axis(es) @@ -1411,6 +1411,12 @@ def __init__(self, objs, axis=0, join='outer', join_axes=None, sample = objs[0] self.objs = objs + # Standardize axis parameter to int + if isinstance(sample, Series): + axis = DataFrame()._get_axis_number(axis) + else: + axis = sample._get_axis_number(axis) + # Need to flip BlockManager axis in the DataFrame special case self._is_frame = isinstance(sample, DataFrame) if self._is_frame: