我尝试用熊猫分析的HTTP日志文件有时会出现意外行。这是我加载数据的方式:
df = pd.read_csv('mylog.log',
sep=r'\s(?=(?:[^"]*"[^"]*")*[^"]*$)(?![^\[]*\])',
engine='python', na_values=['-'], header=None,
usecols=[0, 3, 4, 5, 6, 7, 8,10],
names=['ip', 'time', 'request', 'status', 'size',
'referer','user_agent','req_time'],
converters={'status': int, 'size': int, 'req_time': int})
它对于我拥有的大多数日志(来自同一服务器)都可以正常工作。但是,在加载某些日志时,会引发异常: 要么
TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
或
ValueError: invalid literal for int() with base 10: '"GET /agent/10577/bdl HTTP/1.1"'
为示例起见,这是触发第二个异常的行:
22.111.117.229, 22.111.117.229 - - [19/Sep/2018:22:17:40 +0200] "GET /agent/10577/bdl HTTP/1.1" 204 - "-" "okhttp/3.8.0" apibackend.site.fr 429282
我使用以下(非常慢的)函数来查找内接行的号码:
def search_error_dichotomy(path):
borne_inf = 0
log = open(path)
borne_sup = len(log.readlines())
log.close()
while borne_sup - borne_inf>1:
exceded = False
search_index = (borne_inf + borne_sup) // 2
try:
pd.read_csv(path,...,...,nrows=search_index)
except:
exceded = True
if exceded:
borne_sup = search_index
else:
borne_inf = search_index
return search_index
我想要的是这样的东西:
try:
pd.read_csv(..........................)
except MyError as e:
print(e.row_number)
其中e.row_number是凌乱的行号。
谢谢。
解决方案 所有贡献归功于devssh,他的建议不仅使过程更快,而且使我能够立即获得所有意外行。这是我所做的:
不使用转换器加载数据框。
df = pd.read_csv(path,
sep=r'\s(?=(?:[^"]*"[^"]*")*[^"]*$)(?![^\[]*\])',
engine='python', na_values=['-'], header=None,
usecols=[0, 3, 4, 5, 6, 7, 8,10],
names=['ip', 'time', 'request', 'status', 'size',
'referer', 'user_agent', 'req_time'])
使用.reset_index()添加“索引”列。
df = df.reset_index()
编写自定义函数(与apply一起使用),如果可能的话将转换为int,否则保存 字典中的条目和“索引” rong_lines
wrong_lines = {}
def convert_int_feedback_index(row,col):
try:
ans = int(row[col])
except:
wrong_lines[row['index']] = row[col]
ans = pd.np.nan
return ans
对我要转换的列(例如col ='status','size'或'req_time')使用apply
df[col] = df.apply(convert_int_feedback_index, axis=1, col=col)
答案 0 :(得分:1)
您是否尝试过pd.read_csv(...,nrows = 10)来查看它是否可以在10行上使用?
也许您不应该使用converters
来指定dtypes
。加载DataFrame,然后将dtype应用于df["column"] = df["column"].astype(np.int64)
之类的列或诸如df["column"]=df["column"].apply(lambda x: convert_type(x))
之类的自定义函数,并在函数convert_type中自行处理错误。最后,通过调用df.to_csv("preprocessed.csv", headers=True, index=False)
更新csv。我认为您无法从pd.read_csv
本身获得行号。分隔符本身看起来太复杂了。
或者您可以尝试将csv作为单列DataFrame读取,并使用df["column"].str.extract
使用正则表达式提取列。这样,您可以控制如何引发异常或处理错误的默认值。
df.reset_index()
将为您提供行号。这样,如果您apply to two columns,您还将获得行号。它将为您提供带有行号的索引列。将其与应用于多个列结合使用,您可以自定义所有内容。