【发布时间】:2018-10-07 08:02:53
【问题描述】:
我尝试使用 pandas 分析的 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,否则保存 字典中的条目和“索引” wrong_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 -
在我要转换的列上使用 apply(例如 col = 'status'、'size' 或 'req_time')
df[col] = df.apply(convert_int_feedback_index, axis=1, col=col)
【问题讨论】:
-
有什么异常?
-
@devssh :是的,我尝试使用小 nrows,错误发生在第 271119 行。至于删除转换器并使用 .astype 或 .apply,这听起来是个好主意,但我不知道如何检索发生异常的行号。
-
你看到我对
reset_index的建议了吗?它将为您提供带有行号的index列。将它与apply结合到多个列中,您可以自定义所有内容。您现在似乎默认使用这种替代方法获取行号,对吗? -
@devssh :哇,使用 'df.reset_index()' 确实可以解决问题!非常感谢!