Как выполнить фильтрацию массива?

У меня есть список списков чисел в строковом выражении (после парсинга 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 шт):

Автор решения: Zhihar

Спасибо @splash58, проблема действительно была в том, что внутри данных находилось число, которое выходило за диапазон 32битных чисел (3.290.802.160), поэтому при переводе надо было явно указать, что мне нужны целые побольше:

data = src_data[np.array(src_data[:, 0], np.uint64) >= 0]

Просто думал, что int у numpy такой же неограниченный как у голого python, ну и конечно не думал, что в данных такие большие числа появятся

→ Ссылка
Автор решения: CrazyElf

Вариантов несколько. Можно перевести в 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.

→ Ссылка
Автор решения: MaxU

У меня есть список списков чисел в строковом выражении (после парсинга CSV файла).

Мне кажется многих проблем можно избежать если правильно читать исходные данные, тогда и преобразования типов не нужно будет делать.

import numpy as np

m = np.genfromtxt(filename, dtype=np.uint64)

также можно воспользоваться модулем Pandas:

import pandas as pd

df = pd.read_csv(filename, dtype="uint64")
→ Ссылка