类型转换相关
TypeError: cannot safely cast non-equivalent float64 to uint16
报错原因:
将 "input_address_cnt"(该交易的输入地址数), "addressCnt"(该实体包含的地址数)转换成 UInt16时报错:TypeError: cannot safely cast non-equivalent float64 to uint16
# 将 int 类型的列转换成无符号整型
for int_col in ["input_address_cnt", "addressCnt"]:
spv_node_info_batch[int_col] = pd.to_numeric(
spv_node_info_batch[int_col],
errors="ignore",
downcast="unsigned",
).astype("UInt16")
解决方案
待转换列都是字符串表示的整型,使用 pd.to_numeric 转换成数值型时,因为该列有空值,所以转换成了 float 类型,而计算机存储 float 类型的数据时会有误差,如将 2.0 可能存为 1.99999999999,从而在转换成 UInt 类型时抛出上面的异常。可以在转化之前对其求近似值。如:
# 将 int 类型的列转换成无符号整型
for int_col in ["input_address_cnt", "addressCnt"]:
spv_node_info_batch[int_col] = pd.to_numeric(
spv_node_info_batch[int_col],
errors="ignore",
).round(0).astype("UInt16")
pd.to_numeric() :
- 默认以字符串等形式表示则整型转换成 int64,可以通过参数 downcast="unsigned" 将其转换成 unsigned int 类型;
- 如果是浮点数,就会转化成 float 类型。如果想将其转化成无符号整型,可以接着使用 .round().astype("UInt64");
比较大小时要使用函数,如 eq(), le(), ge()等
如下面的报错,services 通过 pd.to_numeric() 函数将其转换成了无符号整型 UInt64,但是 query 语句汇总使用 == 与 0 进行比较时,自动转换成了 int64,导致数据溢出而报错。如果写成 query("services.eq(0)")
就能正常执行。
csv.Error: line contains NUL
报错相关代码:
with open(input_file, "r", buffering=4 << 20) as fin, open(
output_file, "w", encoding="utf-8", buffering=4 << 20
) as fout:
fin_reader = csv.DictReader(fin, input_file_header, delimiter="\t")
# 因为输入文件中IP列的列名不一致, 只能根据列序号判断具体列名
# file_reader 中的索引从 0 开始, 输入参数 col_idx 是从 1 开始.
for item in fin_reader:
报错分析
待处理文件中包含了 b'\x00',以 'wb'模式打开文件,并追加 b'\x00' 便可以复现该报错。
如果不使用 csv 模块,使用 for line in fin: 可以在 open(file_path, 'r', encoding='utf-8') 模式下正常读取文件。
使用 csv 模块时,该模块不允许出现 \x00 这样的 NULL 字节,因此会报错。
解决方案
不再使用 csv 模块,使用 dict(zip()) 将 key 与 value 创建关联。其余处理步骤和之前一致。
with open(
input_file, "r", encoding="utf-8", buffering=4 << 20, newline=""
) as fin, open(
output_file, "w", encoding="utf-8", buffering=4 << 20, newline=""
) as fout:
input_file_header = [item.strip() for item in input_file_firstline.split("\t")]
for line in fin:
try:
line = line.replace("\x00", "").replace("\0", "")
item = dict(zip(input_file_header, line.strip().split("\t")))
存入数据库时的报错
Data too long for column user_agent
报错原因分析
第1,2张截图:带插入数据中的 user_agent 字段超过了表中 user_agent 字段预定义的长度,所以无法插入。
第3张截图:addr_recv_services 的类型应该是 uint64,其中有个值是 8446744073709551615,超出了MySQL数据库中预定义的 uint的范围(uint32),所以报错,应该将 addr_recv_services 的范围改为 unsigned bigint。
解决方案
将表 btc_flow_version 中 user_agent 字段的长度由 32 改为 1000, 将 addr_recv_services 改为 bigint unsigned 类型。
读取文件时的解析错误
报错信息
pandas.errors.ParserError: Error tokenizing data.C error: EOF inside string starting at row 29425
相关代码
version_info = pd.read_csv(
version_info_file,
sep="\t",
dtype=pd.StringDtype(),
na_values=["{}", "[]", "::", "0.0.0.0"],
usecols=["源IP", "源IPv6", "user_agent", "services", "出现次数"],
)
报错分析
在 user_agent 字段中有一个是以 " 开头,pandas 读取或写 csv/tsv 文件时,默认的 quotechar 是 ", 引用类型(quoting)是 QUOTE_MINIMAL, 因此会将 " 视为 quotechar,并且在该行 user_agent 字段只找到一个 ",所以抛出该错误。
解决方式
在 pd.read_csv() 读取文件时添加参数:quoting=csv.QUOTE_NONE, 将最前的 ' 或 " 视为字符串的一部分,而不是 quotechar。
空值相关
",".join(x.unique().tolist())
报错信息
TypeError: sequence item 0: expected str instance, NAType found
报错分析
user-agent 列中包含 空值,将所有值连成字符串时,导致报错。
解决方法
得到唯一值列表后,应该将其中的空值去掉,再连成字符串。
",".join(x.unique().dropna().tolist())
读取空文件, pandas.errors.EmptyDataError: No columns to parse from file
当读取空文件时, 就会遇到这样的报错.
local variable referenced before assignment
先对要使用的变量做初始化.
序列化与反序列化
TypeError: unhashable type: "set"
chainadmin/process_data/flow_stat.py
相关代码:
for single_file_stats in single_stats_list:
# 将 mining_flow_stats 有的key, 而 stats 没有的key, 加入stats
for key in single_file_stats.keys() - mining_flow_stats.keys():
mining_flow_stats[key] = dict()
报错分析: set 类型的数据不能做 dict 的 key.
具体原因是 get_stats() 函数多进程统计时, key 值会出现 {'矿', '工', 'I', 'P'}. 导致报错.