当我通过skip_footer arg时,Pandas read_csv忽略了列dtypes

Rip*_*ter 10 python csv python-2.7 pandas

当我尝试将csv文件导入数据帧时,pandas(0.13.1)忽略了dtype参数.有没有办法阻止大熊猫自己推断数据类型?

我正在合并几个CSV文件,有时客户包含字母和pandas导入为字符串.当我尝试合并两个数据帧时,我得到一个错误,因为我正在尝试合并两种不同的类型.我需要存储为字符串的一切.

数据片段:

|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  |
Run Code Online (Sandbox Code Playgroud)

进口线:

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

df.dtypes 输出:

ORDER NO    int64
CUSTOMER    int64
dtype: object
Run Code Online (Sandbox Code Playgroud)

Rip*_*ter 19

Pandas 0.13.1默默地忽略了这个dtype论点,因为c engine它不支持skip_footer.这导致熊猫退回到python engine不支持的熊猫身上dtype.

解?使用converters

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

输出:

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
Run Code Online (Sandbox Code Playgroud)

保留原始文件中的前导0,并将所有数据存储为字符串.


Run*_*soe 7

不幸的是,使用转换器或更新的pandas版本并不能解决总是确保read_csv不推断float64 dtype的更普遍的问题.对于pandas 0.15.2,下面的示例(包含带有NULL条目的十六进制表示法的整数的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
Run Code Online (Sandbox Code Playgroud)

指定的dtype对象仅适用于all-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)]
Run Code Online (Sandbox Code Playgroud)

据我所知,至少达到版本0.15.2,没有办法避免在这种情况下对字符串值进行后处理.