如何在不知道 NA 值模式的情况下快速将列转换为数字

Posted

技术标签:

【中文标题】如何在不知道 NA 值模式的情况下快速将列转换为数字【英文标题】:How to convert columns to number quickly without know the NA value patterns 【发布时间】:2015-09-12 20:07:52 【问题描述】:

我有许多列标题相同的 CSV 文件要解析。在这些文件中,可能有几种模式来表示 NA,例如:“-”、“--”、“/”、...

我不知道所有的模式,所以我无法为read_csv() 正确设置na_values 参数。

是否有任何快速方法可以在这些文件中找到所有 NA 模式,或者在不知道所有模式的情况下,我仍然可以将所有列转换为数字?这是我尝试过的:

patterns = set()
for i, fn in enumerate(glob(u"data/*.csv")):
    df = pd.read_csv(fn, encoding="utf-8-sig", usecols=cols, dtype=str, keep_default_na=False)
    df_num = df.convert_objects(convert_numeric=True)
    patterns.update( df[df_num.isnull()].stack().value_counts().index )

但是convert_objects() 很慢。这是一些测试:

read_csv(dtype=str):大约2.2s read_csv() 没有 dtype 参数:大约 2.5 秒 read_csv(dtype=str) + convert_objects(): 8.4s

所以,read_csv() 可以比convert_objects() 更快地将字符串转换为数字。但是如果有一个元素不能转成数字,整列就会变成字符串列。

有没有更快的方法可以在不设置na_values参数的情况下将所有列转换为数字?

【问题讨论】:

您能不能将NaN 的所有已知可能值传递给na_values?否则,我认为您会坚持使用当前的方法 numpy 的 .astype(float) 更快吗? 【参考方案1】:

为什么不直接将“index_col”参数设置为 False。我相信这将导致熊猫从零开始按顺序对您的列进行编号。以下是您的代码在更改后的样子:

patterns = set()
for i, fn in enumerate(glob(u"data/*.csv")):
    df = pd.read_csv(fn, encoding="utf-8-sig", index_col=False, usecols=cols, dtype=str, keep_default_na=False)
    df_num = df.convert_objects(convert_numeric=True)
    patterns.update( df[df_num.isnull()].stack().value_counts().index )

【讨论】:

我不完全确定,但是当使用 index_col=False 时,您可能不再需要 usecols=cols。【参考方案2】:

如果您有 pandas 版本 >= 0.17.0,您可以尝试为每一列应用 pandas.to_numeric(或者您可能知道可疑列):

import pandas as pd

df = pd.DataFrame('a':[1, 2, 3, 4, 'b', 'a', 6], 'b':[0, 1, 2, 'a', 3, 4, 'b'], dtype=str)

一些基准测试:

In [78]: %timeit df.convert_objects(convert_numeric=True)
1000 loops, best of 3: 480 µs per loop

In [79]: %timeit df.apply(pd.to_numeric, errors='coerce')
1000 loops, best of 3: 880 µs per loop

我们可以看到它比 convert_object 慢。让我们将raw=True 传递给apply

In [82]: %timeit df.apply(pd.to_numeric, raw=True, errors='coerce')
1000 loops, best of 3: 288 µs per loop

现在它的速度几乎是convert_objects 的 2 倍。

【讨论】:

以上是关于如何在不知道 NA 值模式的情况下快速将列转换为数字的主要内容,如果未能解决你的问题,请参考以下文章

如何在不丢失科学记数法的情况下将列转换为单个管道分隔的列?

INSERT IF NOT EXISTS 类型函数供我在不将列转换为主键的情况下使用?

将列中的值转换为现有数据框中的行名

如何在不生成 SettingWithCopyWarning 的情况下将列插入 DataFrame

如何在不使用 NA() 的情况下强制 Excel 图表跳过 0?或由 IF 返回“空”

如何在不显示所有结果的最大值的情况下为数学运算以及其他元素选择最大值