Repository: pandas-dev/pandas

Issue:
Pandas Series should provide to_excel method
Hello,

Pandas Series provide `to_csv`method but they doesn't provide `to_excel` method.
Adding `to_excel` will avoid user to convert a `pandas.core.series.Series` to a `pandas.core.frame.DataFrame` in order to output Excel file

DataFrames provide 

```
df.to_clipboard  df.to_hdf        df.to_period     df.to_string
df.to_csv        df.to_html       df.to_pickle     df.to_timestamp
df.to_dense      df.to_json       df.to_records    df.to_wide
df.to_dict       df.to_latex      df.to_sparse
df.to_excel      df.to_msgpack    df.to_sql
df.to_gbq        df.to_panel      df.to_stata
```

Series provide

```
ts.to_clipboard  ts.to_frame      ts.to_period     ts.to_string
ts.to_csv        ts.to_hdf        ts.to_pickle     ts.to_timestamp
ts.to_dense      ts.to_json       ts.to_sparse     ts.tolist
ts.to_dict       ts.to_msgpack    ts.to_sql
```

Kind regards

Pandas Series should provide to_excel method
Hello,

Pandas Series provide `to_csv`method but they doesn't provide `to_excel` method.
Adding `to_excel` will avoid user to convert a `pandas.core.series.Series` to a `pandas.core.frame.DataFrame` in order to output Excel file

DataFrames provide 

```
df.to_clipboard  df.to_hdf        df.to_period     df.to_string
df.to_csv        df.to_html       df.to_pickle     df.to_timestamp
df.to_dense      df.to_json       df.to_records    df.to_wide
df.to_dict       df.to_latex      df.to_sparse
df.to_excel      df.to_msgpack    df.to_sql
df.to_gbq        df.to_panel      df.to_stata
```

Series provide

```
ts.to_clipboard  ts.to_frame      ts.to_period     ts.to_string
ts.to_csv        ts.to_hdf        ts.to_pickle     ts.to_timestamp
ts.to_dense      ts.to_json       ts.to_sparse     ts.tolist
ts.to_dict       ts.to_msgpack    ts.to_sql
```

Kind regards



Discussion:
ok, current work-around is:

`s.to_frame().to_excel()`

pulll-requests welcome

ok, current work-around is:

`s.to_frame().to_excel()`

pulll-requests welcome


Resolving patch:
diff --git a/pandas/core/frame.py b/pandas/core/frame.py
--- a/pandas/core/frame.py
+++ b/pandas/core/frame.py
@@ -105,7 +105,8 @@
     axes_single_arg="{0 or 'index', 1 or 'columns'}",
     optional_by="""
         by : str or list of str
-            Name or list of names which refer to the axis items.""")
+            Name or list of names which refer to the axis items.""",
+    versionadded_to_excel='')
 
 _numeric_only_doc = """numeric_only : boolean, default None
     Include only float, int, boolean data. If None, will attempt to use
@@ -1385,65 +1386,11 @@ def to_csv(self, path_or_buf=None, sep=",", na_rep='', float_format=None,
         if path_or_buf is None:
             return formatter.path_or_buf.getvalue()
 
+    @Appender(_shared_docs['to_excel'] % _shared_doc_kwargs)
     def to_excel(self, excel_writer, sheet_name='Sheet1', na_rep='',
                  float_format=None, columns=None, header=True, index=True,
                  index_label=None, startrow=0, startcol=0, engine=None,
                  merge_cells=True, encoding=None, inf_rep='inf', verbose=True):
-        """
-        Write DataFrame to a excel sheet
-
-        Parameters
-        ----------
-        excel_writer : string or ExcelWriter object
-            File path or existing ExcelWriter
-        sheet_name : string, default 'Sheet1'
-            Name of sheet which will contain DataFrame
-        na_rep : string, default ''
-            Missing data representation
-        float_format : string, default None
-            Format string for floating point numbers
-        columns : sequence, optional
-            Columns to write
-        header : boolean or list of string, default True
-            Write out column names. If a list of string is given it is
-            assumed to be aliases for the column names
-        index : boolean, default True
-            Write row names (index)
-        index_label : string or sequence, default None
-            Column label for index column(s) if desired. If None is given, and
-            `header` and `index` are True, then the index names are used. A
-            sequence should be given if the DataFrame uses MultiIndex.
-        startrow :
-            upper left cell row to dump data frame
-        startcol :
-            upper left cell column to dump data frame
-        engine : string, default None
-            write engine to use - you can also set this via the options
-            ``io.excel.xlsx.writer``, ``io.excel.xls.writer``, and
-            ``io.excel.xlsm.writer``.
-        merge_cells : boolean, default True
-            Write MultiIndex and Hierarchical Rows as merged cells.
-        encoding: string, default None
-            encoding of the resulting excel file. Only necessary for xlwt,
-            other writers support unicode natively.
-        inf_rep : string, default 'inf'
-            Representation for infinity (there is no native representation for
-            infinity in Excel)
-
-        Notes
-        -----
-        If passing an existing ExcelWriter object, then the sheet will be added
-        to the existing workbook.  This can be used to save different
-        DataFrames to one workbook:
-
-        >>> writer = ExcelWriter('output.xlsx')
-        >>> df1.to_excel(writer,'Sheet1')
-        >>> df2.to_excel(writer,'Sheet2')
-        >>> writer.save()
-
-        For compatibility with to_csv, to_excel serializes lists and dicts to
-        strings before writing.
-        """
         from pandas.io.excel import ExcelWriter
         need_save = False
         if encoding is None:
diff --git a/pandas/core/generic.py b/pandas/core/generic.py
--- a/pandas/core/generic.py
+++ b/pandas/core/generic.py
@@ -1016,6 +1016,62 @@ def __setstate__(self, state):
     # ----------------------------------------------------------------------
     # I/O Methods
 
+    _shared_docs['to_excel'] = """
+    Write %(klass)s to a excel sheet
+    %(versionadded_to_excel)s
+    Parameters
+    ----------
+    excel_writer : string or ExcelWriter object
+        File path or existing ExcelWriter
+    sheet_name : string, default 'Sheet1'
+        Name of sheet which will contain DataFrame
+    na_rep : string, default ''
+        Missing data representation
+    float_format : string, default None
+        Format string for floating point numbers
+    columns : sequence, optional
+        Columns to write
+    header : boolean or list of string, default True
+        Write out column names. If a list of string is given it is
+        assumed to be aliases for the column names
+    index : boolean, default True
+        Write row names (index)
+    index_label : string or sequence, default None
+        Column label for index column(s) if desired. If None is given, and
+        `header` and `index` are True, then the index names are used. A
+        sequence should be given if the DataFrame uses MultiIndex.
+    startrow :
+        upper left cell row to dump data frame
+    startcol :
+        upper left cell column to dump data frame
+    engine : string, default None
+        write engine to use - you can also set this via the options
+        ``io.excel.xlsx.writer``, ``io.excel.xls.writer``, and
+        ``io.excel.xlsm.writer``.
+    merge_cells : boolean, default True
+        Write MultiIndex and Hierarchical Rows as merged cells.
+    encoding: string, default None
+        encoding of the resulting excel file. Only necessary for xlwt,
+        other writers support unicode natively.
+    inf_rep : string, default 'inf'
+        Representation for infinity (there is no native representation for
+        infinity in Excel)
+
+    Notes
+    -----
+    If passing an existing ExcelWriter object, then the sheet will be added
+    to the existing workbook.  This can be used to save different
+    DataFrames to one workbook:
+
+    >>> writer = ExcelWriter('output.xlsx')
+    >>> df1.to_excel(writer,'Sheet1')
+    >>> df2.to_excel(writer,'Sheet2')
+    >>> writer.save()
+
+    For compatibility with to_csv, to_excel serializes lists and dicts to
+    strings before writing.
+    """
+
     def to_json(self, path_or_buf=None, orient=None, date_format='epoch',
                 double_precision=10, force_ascii=True, date_unit='ms',
                 default_handler=None, lines=False):
diff --git a/pandas/core/series.py b/pandas/core/series.py
--- a/pandas/core/series.py
+++ b/pandas/core/series.py
@@ -80,7 +80,8 @@
     inplace="""inplace : boolean, default False
         If True, performs operation inplace and returns None.""",
     unique='np.ndarray', duplicated='Series',
-    optional_by='')
+    optional_by='',
+    versionadded_to_excel='\n.. versionadded:: 0.20.0\n')
 
 
 def _coerce_method(converter):
@@ -2619,6 +2620,19 @@ def to_csv(self, path=None, index=True, sep=",", na_rep='',
         if path is None:
             return result
 
+    @Appender(generic._shared_docs['to_excel'] % _shared_doc_kwargs)
+    def to_excel(self, excel_writer, sheet_name='Sheet1', na_rep='',
+                 float_format=None, columns=None, header=True, index=True,
+                 index_label=None, startrow=0, startcol=0, engine=None,
+                 merge_cells=True, encoding=None, inf_rep='inf', verbose=True):
+        df = self.to_frame()
+        df.to_excel(excel_writer=excel_writer, sheet_name=sheet_name,
+                    na_rep=na_rep, float_format=float_format, columns=columns,
+                    header=header, index=index, index_label=index_label,
+                    startrow=startrow, startcol=startcol, engine=engine,
+                    merge_cells=merge_cells, encoding=encoding,
+                    inf_rep=inf_rep, verbose=verbose)
+
     def dropna(self, axis=0, inplace=False, **kwargs):
         """
         Return Series without null values


Test patch:
diff --git a/pandas/io/tests/test_excel.py b/pandas/io/tests/test_excel.py
--- a/pandas/io/tests/test_excel.py
+++ b/pandas/io/tests/test_excel.py
@@ -1078,6 +1078,12 @@ def test_roundtrip(self):
             recons = read_excel(path, index_col=0)
             tm.assert_frame_equal(self.frame, recons)
 
+            # GH 8825 Pandas Series should provide to_excel method
+            s = self.frame["A"]
+            s.to_excel(path)
+            recons = read_excel(path, index_col=0)
+            tm.assert_frame_equal(s.to_frame(), recons)
+
     def test_mixed(self):
         _skip_if_no_xlrd()