Repository: pandas-dev/pandas

Issue:
Conform Series.to_csv to DataFrame.to_csv
Thank you for this awesome package!

#### Problem description
When indexing/selecting/slicing a `DataFrame`, pandas may return a `Series`. Both classes support the `to_csv` method, but the methods have subtle differences. These subtle differences may break your code, or demand a call to `to_frame`. Perhaps it would be beneficial to conform the `Series.to_csv` method to the `DataFrame.to_csv` method?

At least, the following two examples seem relevant (and are the reason I came here):

- `DataFrame.to_csv` accepts the keyword parameter `path_or_buf`. This seems to be completely analogous to the differently named keyword parameter `path` of `Series.to_csv`.
- `DataFrame.to_csv` accepts the keyword parameter `line_terminator`. There does not seem to be an analogous keyword parameter of `Series.to_csv`.

* * *

Addendum: Other differences

The following two keyword parameters are implemented for `DataFrame.to_csv`, but not for `Series.to_csv`: `compression`, `chunksize`. I suppose these are mostly relevant if you have very large dataframes, but I do not see any reason why they should not have analogous methods for Series.

Some of the keyword parameters of `DataFrame.to_csv` are specific to multi-column data and may therefore not make immediate sense for `Series.to_csv`. On the other hand, a user may wish to use quoting in a single-column file in order to maintain conformity with other parts of a bigger project. In this relation, the following keyword parameters are implemented for `DataFrame.to_csv` but do not for `Series.to_csv`:  `quoting`, `quotechar`,`doublequote`, `escapechar`.

#### Output of ``pd.show_versions()``
<details>

INSTALLED VERSIONS
------------------

commit: None
python: 3.6.3.final.0
python-bits: 64
OS: Linux
OS-release: 4.13.0-32-generic
machine: x86_64
processor: x86_64
byteorder: little
LC_ALL:
LANG: en_US.UTF-8
LOCALE: en_US.UTF-8

pandas: 0.22.0
pytest: None
pip: 9.0.1
setuptools: 38.5.1
Cython: None
numpy: 1.14.0
scipy: None
pyarrow: None
xarray: None
IPython: 6.2.1
sphinx: None
patsy: None
dateutil: 2.6.1
pytz: 2017.3
blosc: None
bottleneck: None
tables: None
numexpr: None
feather: None
matplotlib: None
openpyxl: 2.5.0
xlrd: 1.1.0
xlwt: None
xlsxwriter: None
lxml: None
bs4: None
html5lib: None
sqlalchemy: None
pymysql: None
psycopg2: None
jinja2: None
s3fs: None
fastparquet: None
pandas_gbq: None
pandas_datareader: None
None
</details>



Discussion:
@dahlbaek Thanks for opening this issue. I think this all sounds very sensible, and, should also not be too hard to solve. 
As currently `Series.to_csv` just creates a dataframe and then does `DataFrame.to_csv`:

https://github.com/pandas-dev/pandas/blob/2fdf1e256e5e0b7f1fe909629e2f0b7893c8c7c3/pandas/core/series.py#L2924-L2932

So I think we could simply pass through \*\*kwargs to DataFrame.to_csv

I see! If you would like, I would be happy to try my hand at a pull request.
Sure!
xref #18958 : I 100% agree that this should be done.
@jreback @jorisvandenbossche : Three PR's for resolving this issue:

#19745 (@dahlbaek)
#21868 (@gfyoung)
#21896 (@toobaz)

All of them have different implementations.  Thoughts?
As far as I understand, the solution by @gfyoung (#21868) takes care of everything except the reordering of positional arguments. As pointed out by @toobaz [here](https://github.com/pandas-dev/pandas/pull/21868#issuecomment-404666668) (see #21896 for proof of concept), the ordering problem can be solved by noting that `index` should be `True` or `False` while `sep` must be a one-character string. That is, one can determine whether the user is using the old or new signature by checking the type of `sep` (which is the first positional argument following `path_or_buf` in the new signature).

However, as of right now, index also accepts one-character strings (evaluating to `True`), which means there may be code out there passing one-character strings to `index`. I wonder if it would be possible to pave the way for the solution to this problem by first having a release which forces users to pass in boolean valued arguments to `index`?

If one were to first implement something like

```python
if not isinstance(index, bool):
    raise ValueError(
        "{0} is not a valid value for index. "
        "Use True, False or bool({0}) instead."
        .format(repr(index))
    )
```

in `Series.to_csv`, then the solution of @toobaz would be ensured to correctly classify which signature the user had in mind. But maybe this is overthinking it.
> then the solution of @toobaz would be ensured to correctly classify which signature the user had in mind

Doesn't it already? (see last rebase, and [my reply to your comment](https://github.com/pandas-dev/pandas/pull/21896#issuecomment-405003819))
> Doesn't it already? (see last rebase, and my reply to your comment)

No, it does not, sorry, the ambiguity is unavoidable.



> If one were to first implement something like

No, I really don't think we want to do this - not worth the effort (the   ``"y"`` behavior is undocumented).

Resolving patch:
diff --git a/pandas/core/frame.py b/pandas/core/frame.py
--- a/pandas/core/frame.py
+++ b/pandas/core/frame.py
@@ -1714,107 +1714,6 @@ def to_panel(self):
 
         return self._constructor_expanddim(new_mgr)
 
-    def to_csv(self, path_or_buf=None, sep=",", na_rep='', float_format=None,
-               columns=None, header=True, index=True, index_label=None,
-               mode='w', encoding=None, compression='infer', quoting=None,
-               quotechar='"', line_terminator='\n', chunksize=None,
-               tupleize_cols=None, date_format=None, doublequote=True,
-               escapechar=None, decimal='.'):
-        r"""Write DataFrame to a comma-separated values (csv) file
-
-        Parameters
-        ----------
-        path_or_buf : string or file handle, default None
-            File path or object, if None is provided the result is returned as
-            a string.
-        sep : character, default ','
-            Field delimiter for the output file.
-        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 the column names. If a list of strings 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, or False, 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.  If
-            False do not print fields for index names. Use index_label=False
-            for easier importing in R
-        mode : str
-            Python write mode, default 'w'
-        encoding : string, optional
-            A string representing the encoding to use in the output file,
-            defaults to 'ascii' on Python 2 and 'utf-8' on Python 3.
-        compression : {'infer', 'gzip', 'bz2', 'zip', 'xz', None},
-                      default 'infer'
-            If 'infer' and `path_or_buf` is path-like, then detect compression
-            from the following extensions: '.gz', '.bz2', '.zip' or '.xz'
-            (otherwise no compression).
-
-            .. versionchanged:: 0.24.0
-               'infer' option added and set to default
-        line_terminator : string, default ``'\n'``
-            The newline character or character sequence to use in the output
-            file
-        quoting : optional constant from csv module
-            defaults to csv.QUOTE_MINIMAL. If you have set a `float_format`
-            then floats are converted to strings and thus csv.QUOTE_NONNUMERIC
-            will treat them as non-numeric
-        quotechar : string (length 1), default '\"'
-            character used to quote fields
-        doublequote : boolean, default True
-            Control quoting of `quotechar` inside a field
-        escapechar : string (length 1), default None
-            character used to escape `sep` and `quotechar` when appropriate
-        chunksize : int or None
-            rows to write at a time
-        tupleize_cols : boolean, default False
-            .. deprecated:: 0.21.0
-               This argument will be removed and will always write each row
-               of the multi-index as a separate row in the CSV file.
-
-            Write MultiIndex columns as a list of tuples (if True) or in
-            the new, expanded format, where each MultiIndex column is a row
-            in the CSV (if False).
-        date_format : string, default None
-            Format string for datetime objects
-        decimal: string, default '.'
-            Character recognized as decimal separator. E.g. use ',' for
-            European data
-
-        """
-
-        if tupleize_cols is not None:
-            warnings.warn("The 'tupleize_cols' parameter is deprecated and "
-                          "will be removed in a future version",
-                          FutureWarning, stacklevel=2)
-        else:
-            tupleize_cols = False
-
-        from pandas.io.formats.csvs import CSVFormatter
-        formatter = CSVFormatter(self, path_or_buf,
-                                 line_terminator=line_terminator, sep=sep,
-                                 encoding=encoding,
-                                 compression=compression, quoting=quoting,
-                                 na_rep=na_rep, float_format=float_format,
-                                 cols=columns, header=header, index=index,
-                                 index_label=index_label, mode=mode,
-                                 chunksize=chunksize, quotechar=quotechar,
-                                 tupleize_cols=tupleize_cols,
-                                 date_format=date_format,
-                                 doublequote=doublequote,
-                                 escapechar=escapechar, decimal=decimal)
-        formatter.save()
-
-        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,
diff --git a/pandas/core/generic.py b/pandas/core/generic.py
--- a/pandas/core/generic.py
+++ b/pandas/core/generic.py
@@ -9270,6 +9270,115 @@ def first_valid_index(self):
     def last_valid_index(self):
         return self._find_valid_index('last')
 
+    def to_csv(self, path_or_buf=None, sep=",", na_rep='', float_format=None,
+               columns=None, header=True, index=True, index_label=None,
+               mode='w', encoding=None, compression='infer', quoting=None,
+               quotechar='"', line_terminator='\n', chunksize=None,
+               tupleize_cols=None, date_format=None, doublequote=True,
+               escapechar=None, decimal='.'):
+        r"""Write object to a comma-separated values (csv) file
+
+        Parameters
+        ----------
+        path_or_buf : string or file handle, default None
+            File path or object, if None is provided the result is returned as
+            a string.
+            .. versionchanged:: 0.24.0
+                Was previously named "path" for Series.
+        sep : character, default ','
+            Field delimiter for the output file.
+        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 the column names. If a list of strings is given it is
+            assumed to be aliases for the column names
+            .. versionchanged:: 0.24.0
+                Previously defaulted to False for Series.
+        index : boolean, default True
+            Write row names (index)
+        index_label : string or sequence, or False, 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 object uses MultiIndex.  If
+            False do not print fields for index names. Use index_label=False
+            for easier importing in R
+        mode : str
+            Python write mode, default 'w'
+        encoding : string, optional
+            A string representing the encoding to use in the output file,
+            defaults to 'ascii' on Python 2 and 'utf-8' on Python 3.
+        compression : {'infer', 'gzip', 'bz2', 'zip', 'xz', None},
+                      default 'infer'
+            If 'infer' and `path_or_buf` is path-like, then detect compression
+            from the following extensions: '.gz', '.bz2', '.zip' or '.xz'
+            (otherwise no compression).
+
+            .. versionchanged:: 0.24.0
+               'infer' option added and set to default
+        line_terminator : string, default ``'\n'``
+            The newline character or character sequence to use in the output
+            file
+        quoting : optional constant from csv module
+            defaults to csv.QUOTE_MINIMAL. If you have set a `float_format`
+            then floats are converted to strings and thus csv.QUOTE_NONNUMERIC
+            will treat them as non-numeric
+        quotechar : string (length 1), default '\"'
+            character used to quote fields
+        doublequote : boolean, default True
+            Control quoting of `quotechar` inside a field
+        escapechar : string (length 1), default None
+            character used to escape `sep` and `quotechar` when appropriate
+        chunksize : int or None
+            rows to write at a time
+        tupleize_cols : boolean, default False
+            .. deprecated:: 0.21.0
+               This argument will be removed and will always write each row
+               of the multi-index as a separate row in the CSV file.
+
+            Write MultiIndex columns as a list of tuples (if True) or in
+            the new, expanded format, where each MultiIndex column is a row
+            in the CSV (if False).
+        date_format : string, default None
+            Format string for datetime objects
+        decimal: string, default '.'
+            Character recognized as decimal separator. E.g. use ',' for
+            European data
+
+        .. versionchanged:: 0.24.0
+            The order of arguments for Series was changed.
+        """
+
+        df = self if isinstance(self, ABCDataFrame) else self.to_frame()
+
+        if tupleize_cols is not None:
+            warnings.warn("The 'tupleize_cols' parameter is deprecated and "
+                          "will be removed in a future version",
+                          FutureWarning, stacklevel=2)
+        else:
+            tupleize_cols = False
+
+        from pandas.io.formats.csvs import CSVFormatter
+        formatter = CSVFormatter(df, path_or_buf,
+                                 line_terminator=line_terminator, sep=sep,
+                                 encoding=encoding,
+                                 compression=compression, quoting=quoting,
+                                 na_rep=na_rep, float_format=float_format,
+                                 cols=columns, header=header, index=index,
+                                 index_label=index_label, mode=mode,
+                                 chunksize=chunksize, quotechar=quotechar,
+                                 tupleize_cols=tupleize_cols,
+                                 date_format=date_format,
+                                 doublequote=doublequote,
+                                 escapechar=escapechar, decimal=decimal)
+        formatter.save()
+
+        if path_or_buf is None:
+            return formatter.path_or_buf.getvalue()
+
 
 def _doc_parms(cls):
     """Return a tuple of the doc parms."""
diff --git a/pandas/core/series.py b/pandas/core/series.py
--- a/pandas/core/series.py
+++ b/pandas/core/series.py
@@ -17,6 +17,7 @@
 from pandas.core.arrays import ExtensionArray
 from pandas.core.dtypes.common import (
     is_categorical_dtype,
+    is_string_like,
     is_bool,
     is_integer, is_integer_dtype,
     is_float_dtype,
@@ -3765,59 +3766,62 @@ def from_csv(cls, path, sep=',', parse_dates=True, header=None,
 
         return result
 
-    def to_csv(self, path=None, index=True, sep=",", na_rep='',
-               float_format=None, header=False, index_label=None,
-               mode='w', encoding=None, compression='infer', date_format=None,
-               decimal='.'):
-        """
-        Write Series to a comma-separated values (csv) file
-
-        Parameters
-        ----------
-        path : string or file handle, default None
-            File path or object, if None is provided the result is returned as
-            a string.
-        na_rep : string, default ''
-            Missing data representation
-        float_format : string, default None
-            Format string for floating point numbers
-        header : boolean, default False
-            Write out series name
-        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.
-        mode : Python write mode, default 'w'
-        sep : character, default ","
-            Field delimiter for the output file.
-        encoding : string, optional
-            a string representing the encoding to use if the contents are
-            non-ascii, for python versions prior to 3
-        compression : None or string, default 'infer'
-            A string representing the compression to use in the output file.
-            Allowed values are None, 'gzip', 'bz2', 'zip', 'xz', and 'infer'.
-            This input is only used when the first argument is a filename.
-
-            .. versionchanged:: 0.24.0
-               'infer' option added and set to default
-        date_format: string, default None
-            Format string for datetime objects.
-        decimal: string, default '.'
-            Character recognized as decimal separator. E.g. use ',' for
-            European data
-        """
-        from pandas.core.frame import DataFrame
-        df = DataFrame(self)
-        # result is only a string if no path provided, otherwise None
-        result = df.to_csv(path, index=index, sep=sep, na_rep=na_rep,
-                           float_format=float_format, header=header,
-                           index_label=index_label, mode=mode,
-                           encoding=encoding, compression=compression,
-                           date_format=date_format, decimal=decimal)
-        if path is None:
-            return result
+    @Appender(generic.NDFrame.to_csv.__doc__)
+    def to_csv(self, *args, **kwargs):
+
+        names = ["path_or_buf", "sep", "na_rep", "float_format", "columns",
+                 "header", "index", "index_label", "mode", "encoding",
+                 "compression", "quoting", "quotechar", "line_terminator",
+                 "chunksize", "tupleize_cols", "date_format", "doublequote",
+                 "escapechar", "decimal"]
+
+        old_names = ["path_or_buf", "index", "sep", "na_rep", "float_format",
+                     "header", "index_label", "mode", "encoding",
+                     "compression", "date_format", "decimal"]
+
+        if "path" in kwargs:
+            warnings.warn("The signature of `Series.to_csv` was aligned "
+                          "to that of `DataFrame.to_csv`, and argument "
+                          "'path' will be renamed to 'path_or_buf'.",
+                          FutureWarning, stacklevel=2)
+            kwargs["path_or_buf"] = kwargs.pop("path")
+
+        if len(args) > 1:
+            # Either "index" (old signature) or "sep" (new signature) is being
+            # passed as second argument (while the first is the same)
+            maybe_sep = args[1]
+
+            if not (is_string_like(maybe_sep) and len(maybe_sep) == 1):
+                # old signature
+                warnings.warn("The signature of `Series.to_csv` was aligned "
+                              "to that of `DataFrame.to_csv`. Note that the "
+                              "order of arguments changed, and the new one "
+                              "has 'sep' in first place, for which \"{}\" is "
+                              "not a valid value. The old order will cease to "
+                              "be supported in a future version. Please refer "
+                              "to the documentation for `DataFrame.to_csv` "
+                              "when updating your function "
+                              "calls.".format(maybe_sep),
+                              FutureWarning, stacklevel=2)
+                names = old_names
+
+        pos_args = dict(zip(names[:len(args)], args))
+
+        for key in pos_args:
+            if key in kwargs:
+                raise ValueError("Argument given by name ('{}') and position "
+                                 "({})".format(key, names.index(key)))
+            kwargs[key] = pos_args[key]
+
+        if kwargs.get("header", None) is None:
+            warnings.warn("The signature of `Series.to_csv` was aligned "
+                          "to that of `DataFrame.to_csv`, and argument "
+                          "'header' will change its default value from False "
+                          "to True: please pass an explicit value to suppress "
+                          "this warning.", FutureWarning,
+                          stacklevel=2)
+            kwargs["header"] = False  # Backwards compatibility.
+        return self.to_frame().to_csv(**kwargs)
 
     @Appender(generic._shared_docs['to_excel'] % _shared_doc_kwargs)
     def to_excel(self, excel_writer, sheet_name='Sheet1', na_rep='',


Test patch:
diff --git a/pandas/tests/frame/test_to_csv.py b/pandas/tests/frame/test_to_csv.py
--- a/pandas/tests/frame/test_to_csv.py
+++ b/pandas/tests/frame/test_to_csv.py
@@ -893,22 +893,27 @@ def test_to_csv_line_terminators(self):
 
     def test_to_csv_from_csv_categorical(self):
 
-        # CSV with categoricals should result in the same output as when one
-        # would add a "normal" Series/DataFrame.
-        s = Series(pd.Categorical(['a', 'b', 'b', 'a', 'a', 'c', 'c', 'c']))
-        s2 = Series(['a', 'b', 'b', 'a', 'a', 'c', 'c', 'c'])
+        # CSV with categoricals should result in the same output
+        # as when one would add a "normal" Series/DataFrame.
+        s = Series(pd.Categorical(["a", "b", "b", "a", "a", "c", "c", "c"]))
+        s2 = Series(["a", "b", "b", "a", "a", "c", "c", "c"])
         res = StringIO()
-        s.to_csv(res)
+
+        s.to_csv(res, header=False)
         exp = StringIO()
-        s2.to_csv(exp)
+
+        s2.to_csv(exp, header=False)
         assert res.getvalue() == exp.getvalue()
 
         df = DataFrame({"s": s})
         df2 = DataFrame({"s": s2})
+
         res = StringIO()
         df.to_csv(res)
+
         exp = StringIO()
         df2.to_csv(exp)
+
         assert res.getvalue() == exp.getvalue()
 
     def test_to_csv_path_is_none(self):
diff --git a/pandas/tests/io/test_compression.py b/pandas/tests/io/test_compression.py
--- a/pandas/tests/io/test_compression.py
+++ b/pandas/tests/io/test_compression.py
@@ -1,4 +1,5 @@
 import os
+import warnings
 
 import pytest
 
@@ -7,6 +8,14 @@
 import pandas.util.testing as tm
 
 
+def catch_to_csv_depr():
+    # Catching warnings because Series.to_csv has
+    # been deprecated. Remove this context when
+    # Series.to_csv has been aligned.
+
+    return warnings.catch_warnings(record=True)
+
+
 @pytest.mark.parametrize('obj', [
     pd.DataFrame(100 * [[0.123456, 0.234567, 0.567567],
                         [12.32112, 123123.2, 321321.2]],
@@ -15,11 +24,12 @@
 @pytest.mark.parametrize('method', ['to_pickle', 'to_json', 'to_csv'])
 def test_compression_size(obj, method, compression_only):
     with tm.ensure_clean() as path:
-        getattr(obj, method)(path, compression=compression_only)
-        compressed_size = os.path.getsize(path)
-        getattr(obj, method)(path, compression=None)
-        uncompressed_size = os.path.getsize(path)
-        assert uncompressed_size > compressed_size
+        with catch_to_csv_depr():
+            getattr(obj, method)(path, compression=compression_only)
+            compressed_size = os.path.getsize(path)
+            getattr(obj, method)(path, compression=None)
+            uncompressed_size = os.path.getsize(path)
+            assert uncompressed_size > compressed_size
 
 
 @pytest.mark.parametrize('obj', [
@@ -31,16 +41,18 @@ def test_compression_size(obj, method, compression_only):
 def test_compression_size_fh(obj, method, compression_only):
     with tm.ensure_clean() as path:
         f, handles = icom._get_handle(path, 'w', compression=compression_only)
-        with f:
-            getattr(obj, method)(f)
-            assert not f.closed
-        assert f.closed
-        compressed_size = os.path.getsize(path)
+        with catch_to_csv_depr():
+            with f:
+                getattr(obj, method)(f)
+                assert not f.closed
+            assert f.closed
+            compressed_size = os.path.getsize(path)
     with tm.ensure_clean() as path:
         f, handles = icom._get_handle(path, 'w', compression=None)
-        with f:
-            getattr(obj, method)(f)
-            assert not f.closed
+        with catch_to_csv_depr():
+            with f:
+                getattr(obj, method)(f)
+                assert not f.closed
         assert f.closed
         uncompressed_size = os.path.getsize(path)
         assert uncompressed_size > compressed_size
diff --git a/pandas/tests/series/test_io.py b/pandas/tests/series/test_io.py
--- a/pandas/tests/series/test_io.py
+++ b/pandas/tests/series/test_io.py
@@ -37,7 +37,7 @@ def read_csv(self, path, **kwargs):
     def test_from_csv_deprecation(self):
         # see gh-17812
         with ensure_clean() as path:
-            self.ts.to_csv(path)
+            self.ts.to_csv(path, header=False)
 
             with tm.assert_produces_warning(FutureWarning,
                                             check_stacklevel=False):
@@ -45,10 +45,28 @@ def test_from_csv_deprecation(self):
                 depr_ts = Series.from_csv(path)
                 assert_series_equal(depr_ts, ts)
 
+    @pytest.mark.parametrize("arg", ["path", "header", "both"])
+    def test_to_csv_deprecation(self, arg):
+        # see gh-19715
+        with ensure_clean() as path:
+            if arg == "path":
+                kwargs = dict(path=path, header=False)
+            elif arg == "header":
+                kwargs = dict(path_or_buf=path)
+            else:  # Both discrepancies match.
+                kwargs = dict(path=path)
+
+            with tm.assert_produces_warning(FutureWarning):
+                self.ts.to_csv(**kwargs)
+
+                # Make sure roundtrip still works.
+                ts = self.read_csv(path)
+                assert_series_equal(self.ts, ts, check_names=False)
+
     def test_from_csv(self):
 
         with ensure_clean() as path:
-            self.ts.to_csv(path)
+            self.ts.to_csv(path, header=False)
             ts = self.read_csv(path)
             assert_series_equal(self.ts, ts, check_names=False)
 
@@ -65,7 +83,7 @@ def test_from_csv(self):
             ts_h = self.read_csv(path, header=0)
             assert ts_h.name == "ts"
 
-            self.series.to_csv(path)
+            self.series.to_csv(path, header=False)
             series = self.read_csv(path)
             assert_series_equal(self.series, series, check_names=False)
 
@@ -92,13 +110,13 @@ def test_to_csv(self):
         import io
 
         with ensure_clean() as path:
-            self.ts.to_csv(path)
+            self.ts.to_csv(path, header=False)
 
             with io.open(path, newline=None) as f:
                 lines = f.readlines()
             assert (lines[1] != '\n')
 
-            self.ts.to_csv(path, index=False)
+            self.ts.to_csv(path, index=False, header=False)
             arr = np.loadtxt(path)
             assert_almost_equal(arr, self.ts.values)
 
@@ -106,7 +124,7 @@ def test_to_csv_unicode_index(self):
         buf = StringIO()
         s = Series([u("\u05d0"), "d2"], index=[u("\u05d0"), u("\u05d1")])
 
-        s.to_csv(buf, encoding="UTF-8")
+        s.to_csv(buf, encoding="UTF-8", header=False)
         buf.seek(0)
 
         s2 = self.read_csv(buf, index_col=0, encoding="UTF-8")
@@ -116,7 +134,7 @@ def test_to_csv_float_format(self):
 
         with ensure_clean() as filename:
             ser = Series([0.123456, 0.234567, 0.567567])
-            ser.to_csv(filename, float_format="%.2f")
+            ser.to_csv(filename, float_format="%.2f", header=False)
 
             rs = self.read_csv(filename)
             xp = Series([0.12, 0.23, 0.57])
@@ -128,14 +146,14 @@ def test_to_csv_list_entries(self):
         split = s.str.split(r'\s+and\s+')
 
         buf = StringIO()
-        split.to_csv(buf)
+        split.to_csv(buf, header=False)
 
     def test_to_csv_path_is_none(self):
         # GH 8215
         # Series.to_csv() was returning None, inconsistent with
         # DataFrame.to_csv() which returned string
         s = Series([1, 2, 3])
-        csv_str = s.to_csv(path=None)
+        csv_str = s.to_csv(path_or_buf=None, header=False)
         assert isinstance(csv_str, str)
 
     @pytest.mark.parametrize('s,encoding', [