使用pandas read_csv缺少数据

时间:2016-06-03 21:28:29

标签: python csv numpy pandas

我正在尝试读取一些csv文件,其中某些行可能缺少数据块。

当您指定dtype时,这似乎导致pandas read_csv函数出现问题。问题似乎是为了从str转换为dtype指定的pandas只是试图直接转换它。因此,如果缺少某些东西就会崩溃。

随后是MWE(此MWE使用StringIO代替真正的文件;但是,使用真实文件时也会出现问题)

import pandas as pd
import numpy as np
import io

datfile = io.StringIO("12 23 43| | 37| 12.23| 71.3\n12 23 55|X|   |      | 72.3")

names = ['id', 'flag', 'number', 'data', 'data2']
dtypes = [np.str, np.str, np.int, np.float, np.float]

dform = {name: dtypes[ind] for ind, name in enumerate(names)}

colconverters = {0: lambda s: s.strip(), 1: lambda s: s.strip()}

df = pd.read_table(datfile, sep='|', dtype=dform, converters=colconverters, header=None,
                   index_col=0, names=names, na_values=' ')

我运行时遇到的错误是

Traceback (most recent call last):
  File "pandas/parser.pyx", line 1084, in pandas.parser.TextReader._convert_tokens (pandas/parser.c:12580)
TypeError: Cannot cast array from dtype('O') to dtype('int64') according to the rule 'safe'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/aliounis/Repos/stellarpy/source/mwe.py", line 15, in <module>
    index_col=0, names=names, na_values=' ')
  File "/usr/local/lib/python3.5/site-packages/pandas/io/parsers.py", line 562, in parser_f
    return _read(filepath_or_buffer, kwds)
  File "/usr/local/lib/python3.5/site-packages/pandas/io/parsers.py", line 325, in _read
    return parser.read()
  File "/usr/local/lib/python3.5/site-packages/pandas/io/parsers.py", line 815, in read
    ret = self._engine.read(nrows)
  File "/usr/local/lib/python3.5/site-packages/pandas/io/parsers.py", line 1314, in read
    data = self._reader.read(nrows)
  File "pandas/parser.pyx", line 805, in pandas.parser.TextReader.read (pandas/parser.c:8748)
  File "pandas/parser.pyx", line 827, in pandas.parser.TextReader._read_low_memory (pandas/parser.c:9003)
  File "pandas/parser.pyx", line 904, in pandas.parser.TextReader._read_rows (pandas/parser.c:10022)
  File "pandas/parser.pyx", line 1011, in pandas.parser.TextReader._convert_column_data (pandas/parser.c:11397)
  File "pandas/parser.pyx", line 1090, in pandas.parser.TextReader._convert_tokens (pandas/parser.c:12656)
ValueError: invalid literal for int() with base 10: '   '

我有什么办法可以解决这个问题。我查看了文档,但没有看到任何看起来会直接解决此问题的内容。这只是一个需要向熊猫报告的错误吗?

2 个答案:

答案 0 :(得分:1)

试试这个:

import pandas as pd
import numpy as np
import io

datfile = io.StringIO(u"12 23 43| | 37| 12.23| 71.3\n12 23 55|X|   |      | 72.3")

names  = ['id', 'flag', 'number', 'data', 'data2']
dtypes = [np.str, np.str, np.str, np.float, np.float] 
dform  = {name: dtypes[ind] for ind, name in enumerate(names)}

colconverters = {0: lambda s: s.strip(), 1: lambda s: s.strip()}

df     = pd.read_table(datfile, sep='|', dtype=dform, converters=colconverters, header=None, na_values=' ')
df.columns = names

编辑:转换dtypes后导入。

df["number"] = df["data"].astype('int')
df["data"]   = df["data"].astype('float')

您的数据混合了空格和数字。

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2 entries, 0 to 1
Data columns (total 5 columns):
id        2 non-null object
flag      2 non-null object
number    2 non-null object
data      2 non-null object
data2     2 non-null float64
dtypes: float64(1), object(4)
memory usage: 152.0+ bytes

如果你看data它是np.float但转换为对象而data2np.float,直到空白,那么它也会变成对象。

答案 1 :(得分:0)

因此,正如梅林指出的那样,主要的问题是,南方不能成为一个整体,这可能就是为什么大熊猫这种行为开始的原因。我很遗憾没有选择,所以我不得不自己对pandas源代码进行一些更改。我最终不得不将文件parser.pyx的第1087-1096行更改为

        na_count_old = na_count
        print(col_res)
        for ind, row in enumerate(col_res):
            k = kh_get_str(na_hashset, row.strip().encode())
            if k != na_hashset.n_buckets:

                col_res[ind] = np.nan

                na_count += 1

            else:

                col_res[ind] = np.array(col_res[ind]).astype(col_dtype).item(0)

        if na_count_old==na_count:

            # float -> int conversions can fail the above
            # even with no nans
            col_res_orig = col_res
            col_res = col_res.astype(col_dtype)
            if (col_res != col_res_orig).any():
                raise ValueError("cannot safely convert passed user dtype of "
                                 "{col_dtype} for {col_res} dtyped data in "
                                 "column {column}".format(col_dtype=col_dtype,
                                                          col_res=col_res_orig.dtype.name,
                                                          column=i))

基本上遍历列的每个元素,检查每个元素是否包含在na列表中(请注意,我们必须删除这些东西,以便多个空格显示为在na列表中)。如果是,那么该元素被设置为双np.nan。如果它不在na列表中,那么它将被强制转换为为该列指定的原始dtype(这意味着该列将具有多个dtypes)。

虽然这不是一个完美的解决方案(并且可能很慢)但它可以满足我的需求,也许其他有类似问题的人会发现它很有用。