Num py: en utilisant loadtxt ou genfromtxt pour lire une structure déchiquetée
j'ai besoin de lire un fichier ASCII en Python, où un extrait du fichier ressemble à ceci:
E M S T N...
...
9998 1 1 128 10097 10098 10199 10198 20298 20299 20400 20399
9999 1 1 128 10098 10099 10200 10199 20299 20300 20401 20400
10000 1 1 128 10099 10100 10201 10200 20300 20301 20402 20401
10001 1 2 44 2071 2172 12373 12272
10002 1 2 44 2172 2273 12474 12373
le schéma ci-dessus devrait idéalement être le suivant:
array([(9998, 1, 1, 128, (10097, 10098, 10199, 10198, 20298, 20299, 20400, 20399)),
(9999, 1, 1, 128, (10098, 10099, 10200, 10199, 20299, 20300, 20401, 20400)),
(10000, 1, 1, 128, (10099, 10100, 10201, 10200, 20300, 20301, 20402, 20401)),
(10001, 1, 2, 44, (2071, 2172, 12373, 12272)),
(10002, 1, 2, 44, (2172, 2273, 12474, 12373))],
dtype=[('E', '<i4'), ('M', '<i4'), ('S', '<i4'), ('T', '<i4'), ('N', '|O4')])
où le dernier objet, N
, est un tuple
avec entre 2 et 8 entiers.
je voudrais charger cette structure déchiquetée en utilisant soit np.loadtxt
ou np.genfromtxt
" , sauf que je ne suis pas sûr que ce soit possible. Intégrés dans les conseils, ou dois-je faire une coutume split-cast-pour-boucle?
1 réponses
vous avez besoin d'un "split-cast" personnalisé pour boucle, autant que je sache.
en fait, NumPy peut lire des structures imbriquées comme la vôtre, mais elles doivent avoir une forme fixe, comme dans
numpy.loadtxt('data.txt', dtype=[ ('time', np.uint64), ('pos', [('x', np.float), ('y', np.float)]) ])
en essayant de lire vos données avec le dtype dont vous avez besoin, num Py lit seulement le premier numéro de chaque tuple:
dt=[('E', '<i4'), ('M', '<i4'), ('S', '<i4'), ('T', '<i4'), ('N', '|O4')]
print numpy.loadtxt('data.txt', dtype=dt)
imprime ainsi
[(9998, 1, 1, 128, '10097')
(9999, 1, 1, 128, '10098')
(10000, 1, 1, 128, '10099')…]
donc, je dirais allez-y et utilisez un pour boucle à la place de numpy.loadtxt()
.
vous pouvez également utiliser une approche intermédiaire qui pourrait être plus rapide: vous laissez num Py charger le fichier avec le code ci-dessus, puis vous "corriger" manuellement le champ' N':
dt=[('E', '<i4'), ('M', '<i4'), ('S', '<i4'), ('T', '<i4'), ('N', '|O4')]
arr = numpy.loadtxt('data.txt', dtype=dt) # Correctly reads the first 4 columns
with open('data.txt') as input_file:
for (line_num, line) in enumerate(input_file):
arr[line_num]['N'] = tuple(int(x) for x in line.split()[4:]) # Manual setting of the tuple column
Cette approche pourrait être plus rapide que l'analyse de l'ensemble du tableau dans une boucle for. Cela produit le résultat que vous voulez:
[(9998, 1, 1, 128, (10097, 10098, 10199, 10198, 20298, 20299, 20400, 20399))
(9999, 1, 1, 128, (10098, 10099, 10200, 10199, 20299, 20300, 20401, 20400))
(10000, 1, 1, 128, (10099, 10100, 10201, 10200, 20300, 20301, 20402, 20401))
(10001, 1, 2, 44, (2071, 2172, 12373, 12272))
(10002, 1, 2, 44, (2172, 2273, 12474, 1237))]