我从SAP导出的数据有问题。有时,您可以在发布文本中找到换行符。一行中应该是两行,这会导致非常糟糕的数据帧。 最烦人的是,我无法让熊猫意识到这一问题,即使列数小于标题,它也只会读取那些错误的行。
data.txt错误的示例:
MANDT~BUKRS~BELNR~GJAHR
030~01~0100650326
~2016
030~01~0100758751~2017
您可以看到,第一行在0100650326之后有一个错误的换行符。2016属于第一行。第三行是应该的。
如果我导入此文件:
data = pd.read_csv(
path_to_file,
sep='~',
encoding='latin1',
error_bad_lines=True,
warn_bad_lines=True)
我明白了。怎么了?
MANDT BUKRS BELNR GJAHR
0 30.0 1 100650326.0 NaN
1 NaN 2016 NaN NaN
2 30.0 1 100758751.0 2016.0
是否可以解决错误的换行符或告诉熊猫忽略列数小于标题的行?
只需使其完整即可。我想得到这个:
MANDT BUKRS BELNR GJAHR
0 30 1 100650326 2016
1 30 1 100758751 2016
我尝试将和open 一起使用,并将'\ n'(换行符)替换为”(什么都没有),但这会生成一个单一的衬纸文件。这不是故意的。
答案 0 :(得分:0)
您可以进行一些预处理以摆脱不必要的休息。下面是我测试过的示例。
import fileinput
with fileinput.FileInput('input.csv', inplace=True, backup='.orig.bak') as file:
for line in file:
print(line.replace('\n','^'), end='')
with fileinput.FileInput('input.csv', inplace=True, backup='.1.bak') as file:
for line in file:
print(line.replace('^~','~'), end='')
with fileinput.FileInput('input.csv', inplace=True, backup='.2.bak') as file:
for line in file:
print(line.replace('^','\n'), end='')
答案 1 :(得分:0)
正确的方法是在创建时修复文件。如果无法做到这一点,则可以对文件进行预处理或使用包装器。
这是一个使用字节级包装器的解决方案,该包装器组合行,直到您具有正确数量的定界符为止。我使用字节级包装器来利用io模块的类,并尽可能添加自己的代码: <form [formGroup]="testForm">
<input idNumber formControlName="idNumberFormControl" />
<div *ngIf="testForm.get('idNumberFormControl').invalid && testForm.get('idNumberFormControl').errors.customError.inValid"
style="color:red">
{{testForm.get('idNumberFormControl').errors.customError.errMsg}}
</div>
<button type="submit">submit</button>
</form>
从底层字节文件对象中读取行,并合并行以达到预期的效果分隔符的数量(仅覆盖RawIOBase
和readinto
)
readable
然后您可以将代码更改为:
class csv_wrapper(io.RawIOBase):
def __init__(self, base, delim):
self.fd = base # underlying (byte) file object
self.nfields = None
self.delim = ord(delim) # code of the delimiter (passed as a character)
self.numl = 0 # number of line for error processing
self._getline() # load and process the header line
def _nfields(self):
# number of delimiters in current line
return len([c for c in self.line if c == self.delim])
def _getline(self):
while True:
# loads a new line in the internal buffer
self.line = next(self.fd)
self.numl += 1
if self.nfields is None: # store number of delims if not known
self.nfields = self._nfields()
else:
while self.nfields > self._nfields(): # optionaly combine lines
self.line = self.line.rstrip() + next(self.fd)
self.numl += 1
if self.nfields != self._nfields(): # too much here...
print("Too much fields line {}".format(self.numl))
continue # ignore the offending line and proceed
self.index = 0 # reset line pointers
self.linesize = len(self.line)
break
def readinto(self, b):
if len(b) == 0: return 0
if self.index == self.linesize: # if current buffer is exhausted
try: # read a new one
self._getline()
except StopIteration:
return 0
for i in range(len(b)): # store in passed bytearray
if self.index == self.linesize: break
b[i] = self.line[self.index]
self.index += 1
return i
def readable(self):
return True