Как выполнить фильтрацию массива?
У меня есть список списков чисел в строковом выражении (после парсинга CSV файла). Надо оставить только списки, у которых первый элемент больше 0.
Делаю так:
data = filter(lambda record: int(record[0]) >= 0, src_data)
Все ок.
Поскольку дальше будет выборка чисел в NumPy массивы, то решил работать с NumPy массивами сразу, т.е. парсинг CSV файла сразу идет в NumPy массив и дальше работа только с такими данными.
Поэтому, для фильтрации использую следующий код:
data = src_data[np.array(src_data[:, 0], int) >= 0]
И вот тут выдает ошибку:
data = src_data[np.array(src_data[:, 0], int) >= 0]
OverflowError: Python int too large to convert to C long
Для меньшего размера массивов, все нормально, но если мне из массива нужно лишь какое-то небольшое кол-во элементов, то можно сделать так:
data = src_data[:32][np.array(src_data[:32, 0], int) >= 0]
И тоже все нормально.
Но можно ли через numpy сделать нормальную фильтрацию больших массивов или использовать только родной питоновский filter?
P.S. из CSV сразу все не перевожу в тот же int, потому что некоторые столбцы нужны как int, другие как float и т.д..
Ответы (3 шт):
Спасибо @splash58, проблема действительно была в том, что внутри данных находилось число, которое выходило за диапазон 32битных чисел (3.290.802.160), поэтому при переводе надо было явно указать, что мне нужны целые побольше:
data = src_data[np.array(src_data[:, 0], np.uint64) >= 0]
Просто думал, что int у numpy такой же неограниченный как у голого python, ну и конечно не думал, что в данных такие большие числа появятся
Вариантов несколько. Можно перевести в np.float, но нужно подбирать размер, при котором вам хватит разрядов и ничего не исказится (float - не точный тип). Но может хватить и np.int какого-то размера. Можно потестировать разные варианты, код на примере максимума взятого как sys.maxsize+1. Проверю, вылетит ли exception и какова будет разница между тем, что поместилось в массив и sys.maxsize+1:
import sys
import numpy as np
for dtype in [int,np.float,np.float16,np.float32,np.int32,np.int64,np.uint64]:
preds = np.zeros((1, 3), dtype=dtype)
print(preds.dtype, end=': ')
p = [sys.maxsize+1]
try:
preds[0] = p
print(preds[0]-p)
except Exception as ex:
print(ex)
Вывод:
int64: Python int too large to convert to C long
float64: [0. 0. 0.]
float16: [inf inf inf]
float32: [0. 0. 0.]
int32: Python int too large to convert to C long
int64: Python int too large to convert to C long
uint64: [0 0 0]
Пока я писал код вроде уже разобрались в чём дело, но пусть уж будет.
Как видно, в случае с sys.maxsize+1 из int-ов подходит только uint64, но это беззнаковый тип, в случае отрицательных чисел будет фигня. Видимо, всё же float более универсален, начиная с float32.
У меня есть список списков чисел в строковом выражении (после парсинга CSV файла).
Мне кажется многих проблем можно избежать если правильно читать исходные данные, тогда и преобразования типов не нужно будет делать.
import numpy as np
m = np.genfromtxt(filename, dtype=np.uint64)
также можно воспользоваться модулем Pandas:
import pandas as pd
df = pd.read_csv(filename, dtype="uint64")