83937
# 質問

文字列と数値を含む列があります。  
文字列を`numpy.nan`に置換した後のdtypeが、DatFrameの作り方によって異なりました。

### dictからDataFrameを生成した場合

文字列を置換した後のdtypeは`float64`

```

    In [60]: df = pandas.DataFrame({"x": [1.1, "--"]})
    
    In [62]: df
    Out[62]: 
         x
    0  1.1
    1   --
    
    In [63]: df.dtypes
    x    object
    dtype: object
    
    In [64]: df.replace({"--": numpy.nan}, inplace=True)
    
    In [66]: df.dtypes
    Out[66]: 
    x    float64
    dtype: object
    
    
```

### CSVを読み込んでDataFrameを生成した場合

文字列を置換した後のdtypeは`object`

```

    In [66]: df2=pandas.read_csv("input.csv")
    
    In [67]: df2
    Out[67]: 
         x
    0  1.1
    1   --
    
    In [68]: df2.dtypes
    Out[68]: 
    x    object
    dtype: object
    
    In [69]: df2.replace({"--": numpy.nan}, inplace=True)
    
    In [70]: df2
    Out[70]: 
         x
    0  1.1
    1  NaN
    
    In [72]: df2.dtypes
    Out[72]: 
    x    object
    dtype: object
    
    # `1.1`も文字列型だったので、数値である`1.1`を代入する
    In [172]: type(df2["x"].iloc[0])
    Out[172]: str
    
    In [173]: df2["x"].iloc[0]=1.1
    
    In [174]: df2.dtypes
    Out[174]: 
    x    object
    dtype: object
    
    
    
```

# 質問

DatFrameの作り方によって、dtypeが異なるのはなぜでしょうか？  
CSVで読み込んだときはdtypeが固定されるのでしょうか？

# 補足

## pandas version

```

    In [80]: pandas.show_versions()
    
    INSTALLED VERSIONS
    ------------------
    commit           : 73c68257545b5f8530b7044f56647bd2db92e2ba
    python           : 3.9.7.final.0
    python-bits      : 64
    OS               : Linux
    OS-release       : 4.18.0-16-generic
    Version          : #17~18.04.1-Ubuntu SMP Tue Feb 12 13:35:51 UTC 2019
    machine          : x86_64
    processor        : x86_64
    byteorder        : little
    LC_ALL           : None
    LANG             : ja_JP.UTF-8
    LOCALE           : ja_JP.UTF-8
    
    pandas           : 1.3.3
    numpy            : 1.21.2
    pytz             : 2021.3
    dateutil         : 2.8.2
    pip              : 21.2.4
    setuptools       : 57.4.0
    Cython           : None
    pytest           : None
    hypothesis       : None
    sphinx           : None
    blosc            : None
    feather          : None
    xlsxwriter       : None
    lxml.etree       : 4.6.3
    html5lib         : 1.1
    pymysql          : None
    psycopg2         : None
    jinja2           : 3.0.2
    IPython          : 7.28.0
    pandas_datareader: None
    bs4              : None
    bottleneck       : None
    fsspec           : None
    fastparquet      : None
    gcsfs            : None
    matplotlib       : None
    numexpr          : None
    odfpy            : None
    openpyxl         : None
    pandas_gbq       : None
    pyarrow          : 5.0.0
    pyxlsb           : None
    s3fs             : None
    scipy            : 1.7.1
    sqlalchemy       : None
    tables           : None
    tabulate         : None
    xarray           : None
    xlrd             : None
    xlwt             : None
    numba            : None
    
    
```
CC BY-SA 4.0
2021-12-03T02:54:27.857
83931
2021-12-03T12:18:15.707
2021-12-03T12:18:15.707
2238
19524
question
python pandas
DataFrameの作り方によって、dtypeが異なるのはなぜでしょうか？
```

    >>> import pandas as pd
    >>> df2 = pd.read_csv("input.csv")
    >>>
    >>> df2.x.apply(type)
    0    <class 'str'>
    1    <class 'str'>
    Name: x, dtype: object
    
```

[pandas.read_csv — pandas 1.3.4
documentation](https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html#pandas-
read-csv)

> **dtype** : Type name or dict of column -> type, optional  
>  Data type for data or columns. E.g. `{'a': np.float64, 'b': np.int32, 'c':
> 'Int64'}`
>
> Use `str` or `object` together with suitable `na_values` settings to
> preserve and not interpret dtype. **If converters are specified, they will
> be applied INSTEAD of dtype conversion**.
```

    >>> df2 = pd.read_csv("input.csv",
          converters={'x': lambda x: pd.to_numeric(x, errors='ignore')})
    >>> df2.x.apply(type)
    0    <class 'numpy.float64'>
    1              <class 'str'>
    Name: x, dtype: object
    
```
CC BY-SA 4.0
2021-12-03T03:48:44.870
83933
2021-12-03T03:48:44.870
47127
83931
answer
質問タイトルに対する答えとしては、おそらく以下のようなことでpandas.read_csvのparsing
engineの処理を行うか否かで変わってくると推測されます。

**dictからDataFrameを生成した場合**

元となる dict あるいはその中の list を作成した時点で、各要素のデータ型が決まっている。  
DataFrameを作る際に、特に指定しなければそのデータ型がそのまま(あるいは対応するpandasやnumpyのデータ型で？)使われる。

質問記事の場合、DataFrameのパラメータにしたこの時点で`1.1`は`float`、`--`は`string`になっているでしょう。

```

    {"x": [1.1, "--"]}
    
```

なので@metropolisさんの回答とは逆の方向で、以下のようにdict側の処理をCSVに合わせることが出来るでしょう。

```

    df = pandas.DataFrame({"x": ["1.1", "--"]})
    
```

**CSVを読み込んでDataFrameを生成した場合**

CSVのデータはすべて、いったん文字列として読み込まれ、それをpandas.read_csvのparsing処理の中でどのデータ型にするかを決めて変換する。  
pandas.read_csvのparsing engineの特徴により、どのデータ型に変換される(あるいは文字列のまま)かが決まる。  
そして1つの列にデータ型が混在している場合、その結果に一貫性が無くなる場合があるそうです。

[pandas.read_csv](https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html)  
[IO tools (text, CSV, HDF5, …)](https://pandas.pydata.org/pandas-
docs/stable/user_guide/io.html)  
[Specifying column data types](https://pandas.pydata.org/pandas-
docs/stable/user_guide/io.html#specifying-column-data-types)

> Note  
>  In some cases, reading in abnormal data with columns containing mixed
> dtypes will result in an inconsistent dataset. If you rely on pandas to
> infer the dtypes of your columns, the parsing engine will go and infer the
> dtypes for different chunks of the data, rather than the whole dataset at
> once. Consequently, you can end up with column(s) with mixed dtypes.  
>
> 場合によっては、混合dtypeを含む列を含む異常なデータを読み込むと、データセットに一貫性がなくなります。pandasを使用して列のdtypeを推測する場合、解析エンジンは、データセット全体ではなく、データのさまざまなチャンクのdtypeを一度に推測します。その結果、dtypeが混在する列になってしまう可能性があります。

上記説明に続く例では、50万個づつの整数データの途中に文字列データを2つ挟んでCSVファイルを作り、それを読み込ませた結果が737858個の整数データと262144の文字列データとして認識され、列全体としては`int64`と判断されています。  
CSVファイルに書き出す前のDataFrameでデータ型を調べた場合は、100万個の整数データと2個の文字列データでした。

また同様のやり方で整数データの数を前後3個とかに減らすと、CSVファイルを読み込んだ際にすべてが文字列と判断されます。  
おそらく質問の状態はそれと同様の状況でしょう。数値(浮動小数点数)に変換できないデータがあった(かつその割合が多かった？)ので、列全体を文字列扱いにしたものと思われます。

CSV処理側で結果を調整する場合は、@metropolisさん回答のやり方とか、他のパラメータ(dtype,engine等)の組み合わせで行うか、読み込んだ後で色々と変換するメソッドを使う等する必要があるでしょう。
CC BY-SA 4.0
2021-12-03T08:44:21.160
83937
2021-12-03T08:44:21.160
26370
83931
answer