拥有不同版本的None的合理方法?

时间:2019-03-14 15:40:44

标签: python python-3.x numpy nonetype

在Python3中工作。

假设您有一百万只甲虫,您的任务是对它们的斑点大小进行分类。因此,您将创建一个表格,其中每一行都是甲虫,行中的数字代表斑点的大小;

 [[.3, 1.2, 0.5],
  [.6, .7],
  [1.4, .9, .5, .7],
  [.2, .3, .1, .7, .1]]

此外,您决定将其存储在一个numpy数组中,为此您用None填充列表(numpy会将其转换为np.nan)。

 [[.3, 1.2, 0.5, None, None],
  [.6, .7, None, None, None],
  [1.4, .9, .5, .7, None],
  [.2, .3, .1, .7, .1]]

但是有一个问题,由于3个原因之一,表示为None的值可以为None;

  1. 甲虫没有很多斑点;该数量不存在。

  2. 甲虫不会静止不动,也无法测量斑点。

  3. 您还没有全面测量那只甲虫的信息,因此该值尚未分配。

我的问题实际上并不涉及甲虫,但是原理是相同的。 我想要3个不同的None值,这样我就可以使这些缺失值的原因保持明显。我当前的解决方案是使用一个太大的值,从物理上讲不可能,但这并不是一个非常安全的解决方案。

假设您不能使用负数-实际上,我要测量的数量可能是负数。

数据很大,读取速度很重要。

编辑;正确的评论指出,说速度很重要,而不说什么操作没有意义。主成分分析可能将用于变量去相关,聚类算法的欧几里德距离平方计算(但该变量中的数据稀疏)可能需要一些插值。最终是递归神经网络,但这将来自库,因此我只需要将数据转换为输入形式即可。因此,也许没有什么比线性代数更糟糕的了,如果我仔细考虑的话,它们应该都适合RAM。

什么是好的策略?

5 个答案:

答案 0 :(得分:5)

最简单的方法是使用字符串:“不计算”,“未知”和“不适用”。但是,如果要以numpy快速处理,则混合数字/对象的数组不是您的朋友。

我的建议是添加几个与数据形状相同的数组,由0和1组成。因此,数组missing = 1,其中点缺失,否则为0,依此类推,与数组{ {1}}等。

然后,您可以在任何地方使用NaN,然后​​用not_measured屏蔽数据,以轻松找到所需的特定NaN。

答案 1 :(得分:3)

如果只需要一个未知值也不为class MyCreateView(LoginRequiredMixin, generic.CreateView): def form_valid(self, form): form.instance.owner = self.request.user return super().form_valid(form) 的对象,只需创建一个新对象:

None

现在,您可以像使用NOT_APPLICABLE = object() NOT_MEASURED = object() UNKNOWN = object() 一样使用这些值:

None

如果您需要一个可以表示为[1.4, .9, .5, .7, UNKNOWN] ... if value is UNKNOWN: # do something 的值(例如,在float数组中),则可以使用尾数编码的“额外”数据创建一个NaN值。但是,这样做可能不是安全,因为不能保证通过对值的各种操作来保留这些位。

答案 2 :(得分:3)

以下是一种解决方案(免责声明:HACK!),可以避免诸如对象dtype或单独的遮罩之类的减速带:

nan的fp表示周围似乎有很多“死角”:

>>> nan_as_int = np.array(np.nan).view(int)[()]
>>> nan_as_int
9221120237041090560

>>> custom_nan = np.arange(nan_as_int, nan_as_int+10).view(float)
>>> custom_nan
array([nan, nan, nan, nan, nan, nan, nan, nan, nan, nan])

我们创建了十个不同的nan。请注意,这与使用float("nan")创建多个实例不同。这些实例将全部映射到numpy中的相同值,因此一旦放入非对象数组中就无法区分。

即使我们的十个nan具有不同的表示形式,但在浮点级别也很难区分(因为每个定义nan != nan甚至对于唯一的nan也是如此)。所以我们需要一个小帮手:

>>> def which_nan(a):
...     some_nan = np.isnan(a)
...     return np.where(some_nan, np.subtract(a.view(int), nan_as_int, where=some_nan), -1)

示例:

>>> exmpl = np.array([0.1, 1.2, custom_nan[3], custom_nan[0]])
>>> exmpl
array([0.1, 1.2, nan, nan])
>>> which_nan(exmpl)
array([-1, -1,  3,  0], dtype=int64)

也许令人惊讶的是,这似乎在至少一些基本的numpy操作中仍然存在:

>>> which_nan(np.sin(exmpl))
array([-1, -1,  3,  0], dtype=int64)

答案 3 :(得分:2)

在以下问题的评论中,我问为什么不使用np.inf-np.infnp.nan,作者回答这就是他所需要的。

所以我添加了帖子,因为人们更多地关注回复而不是评论。

答案 4 :(得分:1)

建议为每个案例创建三个不同的object实例。

由于您希望这些对象具有NaN的属性,因此您可以尝试创建三个不同的NaN实例。

NOT_APPLICABLE = float("nan")
NOT_MEASURED = float("nan")
UNKNOWN = float("nan")

这是被黑客攻击的极限,因此使用后果自负,但我相信任何Python实现都不会NaN来优化以始终重复使用同一对象。尽管如此,您仍可以添加哨兵条件以在运行前进行检查。

if NOT_APPLICABLE is NOT_MEASURED or NOT_MEASURED is UNKNOWN or UNKNOWN is NOT_APPLICABLE :
    raise ValueError # or try something else

如果此方法有效,则可以让您比较NaN id以检查其含义。

row = [1.0, 2.4, UNKNOWN]

...

if value is UNKNOWN:
    ...

同时,它保留了numpy可能对其数组进行的任何优化。

披露:这是一个不明智的建议,我很想听听其他人的消息。