我之前曾在 numpy issue tracker 和邮件列表中抱怨过此字段名称修改行为。它也在 SO 上的several previous questions 中出现。
事实上,默认情况下np.genfromtxt 会破坏字段名称,即使您通过将字符串列表作为names= 参数传递直接指定它们:
import numpy as np
from io import BytesIO
s = '[5],name with spaces,(x-1)!\n1,2,3\n4,5,6'
x = np.genfromtxt(BytesIO(s), delimiter=',', names=True)
print(repr(x))
# array([(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)],
# dtype=[('5', '<f4'), ('name_with_spaces', '<f4'), ('x1\n1', '<f4')])
names = s.split(',')[:3]
x = np.genfromtxt(BytesIO(s), delimiter=',', skip_header=1, names=names)
print(repr(x))
# array([(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)],
# dtype=[('5', '<f4'), ('name_with_spaces', '<f4'), ('x1\n1', '<f4')])
尽管包含非字母数字字符的字段名称完全合法,但仍会发生这种情况:
x2 = np.empty(2, dtype=dtype)
x2[:] = [(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)]
print(repr(x2))
# array([(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)],
# dtype=[('[5]', '<f4'), ('name with spaces', '<f4'), ('(x-1)!\n1', '<f4')])
这种行为的逻辑让我无法理解。
如您所见,将None 作为deletechars= 参数传递并不足以防止这种情况发生,因为该参数在内部被初始化为numpy._iotools.NameValidator 中的一组默认字符。
但是,您可以传递一个空序列:
x = np.genfromtxt(BytesIO(s), delimiter=',', names=True, deletechars='')
print(repr(x))
# array([(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)],
# dtype=[('[5]', '<f8'), ('name_with_spaces', '<f8'), ('(x-1)!', '<f8')])
这可能是一个空字符串、列表、元组等。只要它的长度为零就没有关系。