You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让pandas.read_csv将空字段转为NaN、保留空字符串?

区分CSV中空字段与空字符串(还原BigQuery导出数据)

你完全是对的——在BigQuery导出的CSV里,无引号的空字段和带引号的""确实对应原表的不同值(NULL和空字符串),但pandas默认的read_csv逻辑会把这两种情况都转成NaN,或者都保留为空字符串,确实让人头疼。不过我们可以通过自定义解析逻辑来实现你的需求,下面一步步说:

解决方案:自定义CSV解析逻辑

因为pandas原生没有提供区分这两种情况的参数,我们可以手动解析CSV行,识别每个字段是否被引号包裹,从而区分无引号的空(转NaN)和带引号的空字符串(保留为空)。这里提供一个适配BigQuery导出格式的实现:

import pandas as pd

def read_bigquery_csv(file_path):
    rows = []
    with open(file_path, 'r', encoding='utf-8') as f:
        # 读取表头
        header = f.readline().strip().split(',')
        for line in f:
            line = line.strip()
            if not line:
                continue
            
            fields = []
            quoted_fields = []
            current_field = []
            in_quote = False
            escape_next = False
            is_quoted = False
            
            for idx, char in enumerate(line):
                # 处理转义字符
                if escape_next:
                    current_field.append(char)
                    escape_next = False
                    continue
                if char == '\\':
                    escape_next = True
                    continue
                
                # 处理引号开关
                if char == '"':
                    if idx == 0 or line[idx-1] == ',':
                        is_quoted = True
                    in_quote = not in_quote
                    continue
                
                # 处理字段分隔符(仅在非引号内生效)
                if char == ',' and not in_quote:
                    fields.append(''.join(current_field))
                    quoted_fields.append(is_quoted)
                    current_field = []
                    is_quoted = False
                    continue
                
                current_field.append(char)
            
            # 处理最后一个字段
            fields.append(''.join(current_field))
            quoted_fields.append(is_quoted)
            
            # 转换字段:无引号的空转NaN,其他保留原始值
            processed_row = []
            for field, was_quoted in zip(fields, quoted_fields):
                if field == '' and not was_quoted:
                    processed_row.append(None)
                else:
                    processed_row.append(field)
            
            rows.append(processed_row)
    
    # 转为DataFrame并调整数据类型(按需)
    df = pd.DataFrame(rows, columns=header)
    df['val'] = pd.to_numeric(df['val'])
    return df

# 使用示例
df = read_bigquery_csv('your_file.csv')
print(df)

运行这段代码后,就能得到你想要的结果:无引号的空字段(第2行的col)转为NaN,带引号的空字符串(第4行的col)保留为空,同时正确解析转义字符(比如第3行的\f\)和带引号的字符串(第5行的"hi")。

关于CSV标准的说明

传统的CSV规范(比如RFC 4180)并没有强制区分无引号空字段和带引号空字符串,不同工具的实现差异很大。但BigQuery在导出CSV时做了明确约定:

  • 原表的NULL值 → 导出为无引号的空字段(比如,2中的第一个空)
  • 原表的空字符串 → 导出为带双引号的空字符串(比如"",4中的第一个字段)

所以你的假设完全正确,这两种情况在这个场景下确实代表不同含义。

Github议题的现状

你提到的4年前的社区讨论确实存在,当时很多用户提出了类似的需求,但截至2024年,pandas的read_csv仍然没有原生支持这种区分——因为不同CSV生成工具的格式差异太大,pandas选择了兼容大多数通用场景的默认行为。所以目前还是需要通过自定义解析来处理BigQuery的这种特殊导出格式。

内容的提问来源于stack exchange,提问作者justhalf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:08:25