获取pandas.read_csv将空字段读取为NaN,将空字符串读取为空字符串

时间:2019-11-29 07:31:54

标签: python pandas csv

这与Get pandas.read_csv to read empty values as empty string instead of nan

相反

给出以下CSV文件:

col,val
"hi
there",1
,2
\f\,3
"",4
"""hi""",5

我希望它读为:

         col  val
0  hi\nthere    1
1        NaN    2
2        \f\    3
3               4
4       "hi"    5

也就是说,将空字段(值2)读取为NaN,同时将空字符串(值4)保留为空字符串。

当前pd.read_csv将val 2和val 4都转换为NaN,或者如果我使用na_filter=False都将其保留为空字符串。

我假设这两种表示形式在CSV中表示不同的内容(空字段与空字符串),所以我假设熊猫也应该能够区分这两种情况。

有没有办法让熊猫区分这两种情况?还是我的假设是错误的,即两种表示形式实际上是相同的? (如果是第二种情况,请给我指出CSV标准)

更多信息,我通过将BigQuery表(具有预期的含义,val 2为空,而val 4为空字符串)导出到CSV中而获得了CSV。我想找回完全相同的表。 因此,此示例不仅是人为的示例,而且在导出为CSV时,BigQuery实际使用了该示例。

编辑:进一步的搜索显示Github issue 4 years ago讨论了类似的观点(例如,参见this comment),其中一位评论者提到存在某种强制性(我不确定他们指的是什么) ,但我理解为空字段和空字符串之间的强制。这还在发生吗?

4 个答案:

答案 0 :(得分:3)

另一个选择是禁用引号,以获取存在空字符串且不存在任何内容的字段。这种情况下的问题是测试中包含换行符的条目。我们需要先删除这些字符,然后合并各行以创建新的数据文件。

在带引号的情况下读取新数据文件时,空值为NaN,空字符串为两个引号。然后,可以使用此数据框设置原始数据框中的NaN,以设置实际的NaN。

import numpy as np
import pandas as pd

with open('./data.csv') as f:
    lines = f.readlines()

# merge lines where the comma is missing
it = iter(lines)
lines2 = [x if ',' in x else x + next(it) for x in it]
# replace \n which are not at the end of the line
lines3 = [l.replace('\n','') + '\n' for l in lines2]
# write new file with merged lines
with open('./data_merged.csv', 'w+') as f:
    f.writelines(lines3)


# read original data
df = pd.read_csv('./data.csv', na_filter=False)
# read merged lines data with quoting off
df_merged = pd.read_csv('./data_merged.csv', quoting=3)

# in df_merged dataframe if is NaN it is a real NaN
# set lines in original df to NaN when in df_merged is NaN
df.loc[df_merged.col.isna(), 'col'] = np.NaN

答案 1 :(得分:3)

pandas.read_csv接受一个quoting参数,该参数控制每个字段的引用行为。该参数接受类型为intcsv.QUOTE_*的值。后者是csv模块中定义的常量。在所有可用选项中,需要注意的一个是csv.QUOTE_NONE。该常量指示reader对象不对引号字符进行特殊处理,这意味着双引号中的字段将按原样读取,并且在解析时不会在字段中添加其他双引号。熊猫设置的默认值为csv.QUOTE_MINIMAL

In [237]: import csv
In [238]: import pandas as pd
In [239]: df = pd.read_csv("test.csv", quoting=csv.QUOTE_NONE)

In [240]: df
Out[240]: 
        col  val
0       "hi  NaN
1    there"  1.0
2       NaN  2.0
3       \f\  3.0
4        ""  4.0
5  """hi"""  5.0

在没有特殊引号的情况下,将空值解析为NaN,并保留带有双引号的空字符串。

但是这种方法存在一个问题:如果任何字段在双引号中包含换行符,则将它们视为单独的字符串。这在csv文件的第一行中很明显,其中“ hi \ nthere”是由熊猫在单独的行中解析的。为了解决这个问题,我首先使用re模块进行了一些预处理。这是将双引号字符串中的所有换行符替换为whitepace所必需的。然后,我写回了相同的文件,并像上面的read_csv一样再次使用它。由于我不知道您的数据的完整格式,因此可能需要更多的正则表达式。但是,对于给定的问题,我得到了所需的输出。

In [314]: with open("test.csv", 'r+') as f:
     ...:     data = f.read()
     ...:     import re
     ...:     pattern = re.compile(r'".*?"', re.DOTALL)
     ...:     data = pattern.sub(lambda x: x.group().replace('\n', ' '), data)
     ...:     f.seek(0)
     ...:     f.write(data)

In [315]: df = pd.read_csv("test.csv", quoting=csv.QUOTE_NONE)

In [316]: df
Out[316]: 
          col  val
0  "hi there"    1
1         NaN    2
2         \f\    3
3          ""    4
4    """hi"""    5

答案 2 :(得分:1)

这里有些丑陋但完整的答案:

import io
import re
import pandas as pd

with open('overflow.csv', 'r') as f:
    with io.StringIO(re.sub(r'(^"",)', "EMPTY_STR,", f.read(), flags=re.MULTILINE)) as ff:
        with io.StringIO(re.sub(r'(,"",)', ",EMPTY_STR,", ff.read(), flags=re.MULTILINE)) as fff:
            with io.StringIO(re.sub(r'(,""$)', ",EMPTY_STR", fff.read(), flags=re.MULTILINE)) as ffff:
                df = pd.read_csv(ffff)

df= df.replace('EMPTY_STR', '')

re.sub()EMPTY_STR替换空字符串,以后可以用实际的空字符串替换。对于所有三种可能的事件类型(行的开头,中间和行),必须调用三次。

真正的空单元格被搁置,并且确实被解释为NaN

答案 3 :(得分:0)

在创建BigQuery csv导出时,是否有任何其他方法可以将空字符串替换为其他字符串?像将""替换为"EMPTY_STR"一样?然后,您可以在使用.read_csv()时使用转换器函数将其替换为空字符串。