在pandas中忽略列数据中的分隔符

1 投票
1 回答
35 浏览
提问于 2025-04-14 16:25

我有一个输入的CSV文件,除了我们用数据框对象修改的字段外,不应该被pandas自动修改。比如,我们使用逗号(,)作为分隔符。这个文件可能包含:

  • 没有引号的数据:
    • plah
    • blah
  • 引号可以随意出现,次数也不固定。比如:
    • "plah"
    • ""plah
    • """plah"
    • ""pl""ah""
  • 单个列的数据中可能包含分隔符(但这些数据的左右两边一定会有引号)。比如:
    • "plah,blah"
    • ""plah"",""blah"

在这些情况下,pandas不应该丢失引号,也不应该把单个引号列中的逗号(,)当作是不同的列。

可复现的代码:

# Input file
csv_data = '''A,B,C,D,E
234,mno,C22,U,
567,pqr,"C3""",U,5555
999,abc,"C99",D,9999
678,bns,"C6,C7",F,6666
789,bcd,""""C77,T,7777
'''

# Load CSV data into dataframes
df = pd.read_csv(StringIO(csv_data), header=0, dtype=str, keep_default_na=False, engine='python', sep=',', quoting=3)

df.to_csv('output.txt', sep=',', index=False, header=True, quoting=3)

我遇到了错误:

ParserError: Expected 5 fields in line 5, saw 6

期望结果:

A,B,C,D,E
234,mno,C22,U,
567,pqr,"C3""",U,5555
999,abc,"C99",D,9999
678,bns,"C6,C7",F,6666
789,bcd,""""C77,T,7777

1 个回答

2

你关闭了引号功能(quoting=3/quoting=csv.QUOTE_NONE),但是数据的第四行

678,bns,"C6,C7",F,6666

很可能应该有一个被引号包围的字段 "C6,C7"

所以你应该这样读取它:

678   bns   "C6   C7"   F   6666

你不能把引号当作分隔符,同时又把它们保留在导入的数据里。

主要的问题是你的CSV文件不合法。你要么使用引号作为引号字符,要么使用普通字符,它们不能同时存在。

一个解决办法是,如果你只有这一种双重使用引号的情况,可以尝试用两种模式读取文件两次,然后用concat把它们合并,再用drop_duplicates去掉重复项,除了C列:

df1 = pd.read_csv(StringIO(csv_data), header=0, dtype=str,
                  keep_default_na=False, engine='python', sep=',',
                  quoting=3, on_bad_lines='skip')
df2 = pd.read_csv(StringIO(csv_data), header=0, dtype=str,
                  keep_default_na=False, engine='python', sep=',',
                  quoting=0, on_bad_lines='skip')

out = (pd.concat([df1, df2])
         .drop_duplicates(['A', 'B', 'D', 'E'], ignore_index=True)
      )

注意,这样做不会保持原始行的顺序。

输出:

     A    B        C  D     E
0  234  mno      C22  U      
1  567  pqr   "C3"""  U  5555
2  999  abc    "C99"  D  9999
3  789  bcd  """"C77  T  7777
4  678  bns    C6,C7  F  6666

撰写回答