web-dev-qa-db-ja.com

Pandas read_csvは、skip_footerargを渡すときに列のdtypeを無視します

Csvファイルをデータフレームにインポートしようとするとpandas(0.13.1)はdtypeパラメーターを無視します。pandasの推測を停止する方法はありますか?それ自体のデータ型?

複数のCSVファイルをマージしていますが、顧客に文字が含まれている場合があり、pandas imports asstring。2つのデータフレームをマージしようとすると、2つの異なるタイプをマージしようとしているため、エラーが発生します。 。すべてを文字列として保存する必要があります。

データスニペット:

|WAREHOUSE|ERROR|CUSTOMER|ORDER NO|
|---------|-----|--------|--------|
|3615     |     |03106   |253734  |
|3615     |     |03156   |290550  |
|3615     |     |03175   |262207  |
|3615     |     |03175   |262207  |
|3615     |     |03175   |262207  |
|3615     |     |03175   |262207  |
|3615     |     |03175   |262207  |
|3615     |     |03175   |262207  |
|3615     |     |03175   |262207  |

インポートライン:

df = pd.read_csv("SomeFile.csv", 
                 header=1,
                 skip_footer=1, 
                 usecols=[2, 3], 
                 dtype={'ORDER NO': str, 'CUSTOMER': str})

df.dtypesこれを出力します:

ORDER NO    int64
CUSTOMER    int64
dtype: object
10
Ripster

c engineskip_footerをサポートしていないため、Pandas0.13.1はdtype引数を黙って無視しました。これにより、Pandasはdtypeをサポートしないpython engineにフォールバックしました。

解決? convertersを使用します

df = pd.read_csv('SomeFile.csv', 
                 header=1,
                 skip_footer=1, 
                 usecols=[2, 3], 
                 converters={'CUSTOMER': str, 'ORDER NO': str},
                 engine='python')

出力:

In [1]: df.dtypes
Out[2]:
CUSTOMER    object
ORDER NO    object
dtype: object

In [3]: type(df['CUSTOMER'][0])
Out[4]: str

In [5]: df.head()
Out[6]:
  CUSTOMER ORDER NO
0    03106   253734
1    03156   290550
2    03175   262207
3    03175   262207
4    03175   262207

元のファイルの先頭の0は保持され、すべてのデータは文字列として保存されます。

19
Ripster

残念ながら、コンバーター以降のpandasバージョンを使用しても、read_csvがfloat64dtypeを推測しないことを常に保証するというより一般的な問題は解決されません。pandas 0.15。 2、次の例では、NULLエントリを含む16進表記の整数を含むCSVを使用して、名前が意味するものにコンバーターを使用すると、dtypeの指定に干渉することを示しています。

In [1]: df = pd.DataFrame(dict(a = ["0xff", "0xfe"], b = ["0xfd", None], c = [None, "0xfc"], d = [None, None]))
In [2]: df.to_csv("H:/tmp.csv", index = False)
In [3]: ef = pd.read_csv("H:/tmp.csv", dtype = {c: object for c in "abcd"}, converters = {c: lambda x: None if x == "" else int(x, 16) for c in "abcd"})
In [4]: ef.dtypes.map(lambda x: x)
Out[4]:
a      int64
b    float64
c    float64
d     object
dtype: object

指定されたオブジェクトのdtypeは、すべてNULLの列に対してのみ尊重されます。この場合、float64値は整数に変換できますが、鳩の巣原理によ​​り、64ビット整数のすべてをfloat64として表すことができるわけではありません。

このより一般的なケースで私が見つけた最善の解決策は、pandasを取得して、すでに説明したように、潜在的に問題のある列を文字列として読み取り、変換が必要な値でスライスを変換することです(列での変換。これもまた、自動dtype = float64推論になります)。

In [5]: ff = pd.read_csv("H:/tmp.csv", dtype = {c: object for c in "bc"}, converters = {c: lambda x: None if x == "" else int(x, 16) for c in "ad"})
In [6]: ff.dtypes
Out[6]:
a     int64
b    object
c    object
d    object
dtype: object
In [7]: for c in "bc":
   .....:     ff.loc[~pd.isnull(ff[c]), c] = ff[c][~pd.isnull(ff[c])].map(lambda x: int(x, 16))
   .....:
In [8]: ff.dtypes
Out[8]:
a     int64
b    object
c    object
d    object
dtype: object
In [9]: [(ff[c][i], type(ff[c][i])) for c in ff.columns for i in ff.index]
Out[9]:
[(255, numpy.int64),
 (254, numpy.int64),
 (253L, long),
 (nan, float),
 (nan, float),
 (252L, long),
 (None, NoneType),
 (None, NoneType)]

私が判断できた限りでは、少なくともバージョン0.15.2までは、このような状況で文字列値の後処理を回避する方法はありません。

7
Rune Lyngsoe