Repository: pandas-dev/pandas

Issue:
API: deprecate combineAdd and combineMult methods?
On a DataFrame, we have the [`combineAdd`](http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.combineAdd.html) and [`combineMult`](http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.combineMult.html) methods:
- they are a redundant, as they are defined as `self.add(other, fill_value=0.)` and `self.mul(other, fill_value=1.)` (that is the actual implementation), which is also just cleaner to use IMHO.
- they have awkward (and non-pep8) names
- I assume they are not used a lot (I found 3 relevant references on StackOverflow for combineAdd ([SO1](http://stackoverflow.com/questions/28421137/subtract-two-dataframes-with-non-overlapping-indexes/28421255#28421255), [SO2](http://stackoverflow.com/questions/27744908/computing-sum-of-pandas-dataframes/27746836#27746836) and [SO2](http://stackoverflow.com/questions/20927701/pandas-numpy-how-to-turn-column-data-into-sparse-matrix/20929504#20929504), which is more than I expected), and none for combineMult

Therefore, I was thinking we could maybe deprecate these (as kind of clean-up)?



Discussion:
yeh they have a 'deprecated stuff' comment, but were not actually deprecated, sigh :( so let's deprecate and remove in next version.

> yeh they have a 'deprecated stuff' comment,

Ah, yes, you mean in the codebase (as in the docstring nothing is said about that ..)

Will do a PR in a few days if no one complains

+1 for deprecation.

yes I think these are pretty old methods, and superfluous with `.add,.mult`. Let's just actually deprecate them.


Resolving patch:
diff --git a/pandas/core/frame.py b/pandas/core/frame.py
--- a/pandas/core/frame.py
+++ b/pandas/core/frame.py
@@ -4900,6 +4900,8 @@ def isin(self, values):
 
     def combineAdd(self, other):
         """
+        DEPRECATED. Use ``DataFrame.add(other, fill_value=0.)`` instead.
+
         Add two DataFrame objects and do not propagate
         NaN values, so if for a (column, time) one frame is missing a
         value, it will default to the other frame's value (which might
@@ -4912,11 +4914,21 @@ def combineAdd(self, other):
         Returns
         -------
         DataFrame
+
+        See also
+        --------
+        DataFrame.add
+
         """
+        warnings.warn("'combineAdd' is deprecated. Use "
+                      "'DataFrame.add(other, fill_value=0.)' instead",
+                      FutureWarning, stacklevel=2)
         return self.add(other, fill_value=0.)
 
     def combineMult(self, other):
         """
+        DEPRECATED. Use ``DataFrame.mul(other, fill_value=1.)`` instead.
+
         Multiply two DataFrame objects and do not propagate NaN values, so if
         for a (column, time) one frame is missing a value, it will default to
         the other frame's value (which might be NaN as well)
@@ -4928,7 +4940,15 @@ def combineMult(self, other):
         Returns
         -------
         DataFrame
+
+        See also
+        --------
+        DataFrame.mul
+
         """
+        warnings.warn("'combineMult' is deprecated. Use "
+                      "'DataFrame.mul(other, fill_value=1.)' instead",
+                      FutureWarning, stacklevel=2)
         return self.mul(other, fill_value=1.)
 
 


Test patch:
diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py
--- a/pandas/tests/test_frame.py
+++ b/pandas/tests/test_frame.py
@@ -11787,61 +11787,65 @@ def test_update_from_non_df(self):
         assert_frame_equal(df, expected)
 
     def test_combineAdd(self):
-        # trivial
-        comb = self.frame.combineAdd(self.frame)
-        assert_frame_equal(comb, self.frame * 2)
 
-        # more rigorous
-        a = DataFrame([[1., nan, nan, 2., nan]],
-                      columns=np.arange(5))
-        b = DataFrame([[2., 3., nan, 2., 6., nan]],
-                      columns=np.arange(6))
-        expected = DataFrame([[3., 3., nan, 4., 6., nan]],
-                             columns=np.arange(6))
-
-        result = a.combineAdd(b)
-        assert_frame_equal(result, expected)
-        result2 = a.T.combineAdd(b.T)
-        assert_frame_equal(result2, expected.T)
-
-        expected2 = a.combine(b, operator.add, fill_value=0.)
-        assert_frame_equal(expected, expected2)
-
-        # corner cases
-        comb = self.frame.combineAdd(self.empty)
-        assert_frame_equal(comb, self.frame)
-
-        comb = self.empty.combineAdd(self.frame)
-        assert_frame_equal(comb, self.frame)
-
-        # integer corner case
-        df1 = DataFrame({'x': [5]})
-        df2 = DataFrame({'x': [1]})
-        df3 = DataFrame({'x': [6]})
-        comb = df1.combineAdd(df2)
-        assert_frame_equal(comb, df3)
-
-        # mixed type GH2191
-        df1 = DataFrame({'A': [1, 2], 'B': [3, 4]})
-        df2 = DataFrame({'A': [1, 2], 'C': [5, 6]})
-        rs = df1.combineAdd(df2)
-        xp = DataFrame({'A': [2, 4], 'B': [3, 4.], 'C': [5, 6.]})
-        assert_frame_equal(xp, rs)
+        with tm.assert_produces_warning(FutureWarning):
+            # trivial
+            comb = self.frame.combineAdd(self.frame)
+            assert_frame_equal(comb, self.frame * 2)
+
+            # more rigorous
+            a = DataFrame([[1., nan, nan, 2., nan]],
+                          columns=np.arange(5))
+            b = DataFrame([[2., 3., nan, 2., 6., nan]],
+                          columns=np.arange(6))
+            expected = DataFrame([[3., 3., nan, 4., 6., nan]],
+                                 columns=np.arange(6))
+
+            result = a.combineAdd(b)
+            assert_frame_equal(result, expected)
+            result2 = a.T.combineAdd(b.T)
+            assert_frame_equal(result2, expected.T)
+
+            expected2 = a.combine(b, operator.add, fill_value=0.)
+            assert_frame_equal(expected, expected2)
+
+            # corner cases
+            comb = self.frame.combineAdd(self.empty)
+            assert_frame_equal(comb, self.frame)
+
+            comb = self.empty.combineAdd(self.frame)
+            assert_frame_equal(comb, self.frame)
+
+            # integer corner case
+            df1 = DataFrame({'x': [5]})
+            df2 = DataFrame({'x': [1]})
+            df3 = DataFrame({'x': [6]})
+            comb = df1.combineAdd(df2)
+            assert_frame_equal(comb, df3)
+
+            # mixed type GH2191
+            df1 = DataFrame({'A': [1, 2], 'B': [3, 4]})
+            df2 = DataFrame({'A': [1, 2], 'C': [5, 6]})
+            rs = df1.combineAdd(df2)
+            xp = DataFrame({'A': [2, 4], 'B': [3, 4.], 'C': [5, 6.]})
+            assert_frame_equal(xp, rs)
 
         # TODO: test integer fill corner?
 
     def test_combineMult(self):
-        # trivial
-        comb = self.frame.combineMult(self.frame)
 
-        assert_frame_equal(comb, self.frame ** 2)
+        with tm.assert_produces_warning(FutureWarning):
+            # trivial
+            comb = self.frame.combineMult(self.frame)
 
-        # corner cases
-        comb = self.frame.combineMult(self.empty)
-        assert_frame_equal(comb, self.frame)
+            assert_frame_equal(comb, self.frame ** 2)
 
-        comb = self.empty.combineMult(self.frame)
-        assert_frame_equal(comb, self.frame)
+            # corner cases
+            comb = self.frame.combineMult(self.empty)
+            assert_frame_equal(comb, self.frame)
+
+            comb = self.empty.combineMult(self.frame)
+            assert_frame_equal(comb, self.frame)
 
     def test_combine_generic(self):
         df1 = self.frame