【问题标题】:Skip rows with missing values in read_csv跳过 read_csv 中缺失值的行
【发布时间】:2016-08-07 21:12:55
【问题描述】:

我有一个非常大的 csv,我需要读取它。为了加快速度并节省 RAM 使用量,我使用 read_csv 并将某些列的 dtype 设置为 np.uint32。问题是某些行缺少值,而 pandas 使用浮点数来表示这些值。

  1. 是否可以简单地跳过缺少值的行?我知道我可以在读取整个文件后执行此操作,但这意味着在此之前我无法设置 dtype,因此会使用太多 RAM。
  2. 是否可以将缺失值转换为我在读取数据期间选择的其他值?

【问题讨论】:

  • 你会考虑预处理你的数据,例如'grep -v ,, infile.csv > goodfile.csv`吗?这样,您也许可以更快地消除“坏”行。但这取决于 all 列中的空值是无效还是仅部分无效。
  • @JohnZwinck 你能在基于 Windows 的机器上使用“grep”吗?
  • @Merlin:是的,我可以。
  • @JohnZwinck 不是你这个人,而是全球的你。 (不再是windows用户。)你认为OP可以吗?
  • @JohnZwinck 我可以进行预处理,但如果可能的话,我希望将所有处理都放在一个文件中。也许 Python 可以调用 grep 并将输出通过管道传输到 read_csv?

标签: python pandas


【解决方案1】:

如果你可以在阅读过程中用0 填充NaN,那就太好了。也许 Pandas 的 git-hub 中的功能请求是按顺序排列的......

使用转换器函数

但是,目前,您可以定义自己的函数来执行此操作并将其传递给 read_csv 中的 converters 参数:

def conv(val):
    if val == np.nan:
        return 0 # or whatever else you want to represent your NaN with
    return val

df = pd.read_csv(file, converters={colWithNaN : conv}, dtypes=...)

请注意,converters 采用 dict,因此您需要为每个需要处理 NaN 的列指定它。如果很多列受到影响,它可能会有点烦人。您可以指定列名或数字作为键。

另请注意,这可能会降低您的read_csv 性能,具体取决于converters 函数的处理方式。此外,如果您只有一列需要在读取期间处理 NaN,您可以跳过正确的函数定义并改用 lambda 函数:

df = pd.read_csv(file, converters={colWithNaN : lambda x: 0 if x == np.nan else x}, dtypes=...)

分块阅读

您还可以读取小块文件,将它们拼接在一起以获得最终输出。你可以用这种方式做很多事情。这是一个说明性示例:

result = pd.DataFrame()
df = pd.read_csv(file, chunksize=1000)
for chunk in df:
    chunk.dropna(axis=0, inplace=True) # Dropping all rows with any NaN value
    chunk[colToConvert] = chunk[colToConvert].astype(np.uint32)
    result = result.append(chunk)
del df, chunk

请注意,此方法不会严格复制数据。有一段时间,chunk 中的数据存在两次,就在result.append 语句之后,但只有chunksize 行重复,这是一个公平的交易。这种方法也可能比使用转换器功能更快。

【讨论】:

  • 我想这取决于表中是否有任何想要的输入中的 NaN。
  • @Jasen,嗯,这是有代表性的伪代码。这并不意味着更换。可能正在读取的数据是空的,所以if语句应该改为if val is None:。也许它有其他的表现形式......
  • 谢谢。这回答了问题 2。这个方法可以用来回答问题 1。不知何故?
  • 我不认为您可以使用pandas.read_csv 来跳过缺少值的行。如果一行中的所有值都丢失了,则有一个 skip_blank_lines kwag 默认设置为 True,因此您无能为力。您是否想过分块读取文件,对其进行处理并将它们缝合在一起?我也可以编辑我的答案以包含该方法。
  • 如果您认为您的问题已得到解答,请标记为已回答。谢谢。
【解决方案2】:

Pandas 中没有这样做的功能。您可以像这样在常规 Python 中实现它:

import csv
import pandas as pd

def filter_records(records):
    """Given an iterable of dicts, converts values to int.
    Discards any record which has an empty field."""

    for record in records:
        for k, v in record.iteritems():
            if v == '':
                break
            record[k] = int(v)
        else: # this executes whenever break did not
            yield record

with open('t.csv') as infile:
    records = csv.DictReader(infile)
    df = pd.DataFrame.from_records(filter_records(records))

Pandas 无论如何都在内部使用csv 模块。如果上面的性能有问题,您可能可以使用 Cython(Pandas 也使用)加速它。

【讨论】:

  • 这似乎在 RAM 中创建了两个输入副本?第一个副本“记录”具有类型转换之前的整个文件。这正是我想要避免的。
  • 可能pandas.read_csv也容易出现数据重复。至少它是,如果您阅读大熊猫的创造者 Wes McKinny 的 [this blog][1]。但请注意,该博客写于 2012 年 10 月,正如博客上的免责声明所说,已经有一段时间了,大部分信息已经过时了。我不知道现代的、闪亮的read_csv 在内存管理方面能做什么。 [1]:wesmckinney.com/blog/…
【解决方案3】:

如果您显示一些数据,那么 ppl 可能会有所帮助。

pd.read_csv('FILE', keep_default_na=False)

对于初学者来说,试试这些:

http://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_csv.html

na_values : str or list-like or dict, default None
Additional strings to recognize as NA/NaN. If dict passed, specific per-column NA values. By default the following values are interpreted as NaN: ‘’, ‘#N/A’, ‘#N/A N/A’, ‘#NA’, ‘-1.#IND’, ‘-1.#QNAN’, ‘-NaN’, ‘-nan’, ‘1.#IND’, ‘1.#QNAN’, ‘N/A’, ‘NA’, ‘NULL’, ‘NaN’, ‘nan’.

keep_default_na : bool, default True
If na_values are specified and keep_default_na is False the default NaN values are overridden, otherwise they’re appended to.

na_filter : boolean, default True
    Detect missing value markers (empty strings and the value of na_values). In data without any NAs, passing na_filter=False can improve the performance of reading a large file

【讨论】:

    猜你喜欢
    • 2013-11-29
    • 1970-01-01
    • 2018-07-27
    • 2019-01-02
    • 1970-01-01
    • 2017-02-10
    • 2015-02-04
    相关资源
    最近更新 更多