根据特定值从2D numpy数组中移除元素

2024-05-14 15:40:05 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个包含机器学习数据的numpy数组,有超过500000行。在

看起来像这样:

[[1,2,3,4,1,0.3], [1,3,2,4,0,0.9], [3,2,5,4,0,0.8] ...]

前4个值是参数,第5个是类,第6个是0类的概率。在

问题是,数据是强极化的——类0的行比类1的行多20倍。这不利于学习,我需要用类0删除许多行。但是,为了获得最佳结果,我不想随机删除数据,而是这样:

我需要尽可能长地删除索引5(类0的概率)上值最高的行,因为索引4(类)中有相同数量的0和1行。在

如果有比循环更好的解决方案,那就太棒了。在

这有点复杂,所以如果你有更多的问题,尽管问。在


Tags: 数据numpy机器参数数量数组解决方案概率
3条回答

让我们生成一些假数据

In [84]: import numpy as np
In [85]: from random import randint, random
In [86]: data = [[1,2,3,4, randint(0,2), random()] for _ in range(20)]

把所有的2类行都改为0类行,这样我们(可能)有很多零值。在

^{pr2}$

在你的例子中,你使用了一个结构化数组,所以我还有一个结构化数组。。。为了构造一个结构化数组,我们需要一个元组列表,而不是一个列表列表

In [88]: data=[tuple(r) for r in data]
In [89]: dtype = [('a', int), ('b', int), ('c', int), ('d', int), ('class', int), ('p', float)]
In [90]: a = np.array(data, dtype=dtype)
In [91]: a
Out[91]: 
array([(1, 2, 3, 4, 0,  0.92339399), (1, 2, 3, 4, 0,  0.04958431),
       (1, 2, 3, 4, 0,  0.83051072), (1, 2, 3, 4, 1,  0.3753248 ),
       (1, 2, 3, 4, 0,  0.44558775), (1, 2, 3, 4, 0,  0.49603591),
       (1, 2, 3, 4, 0,  0.86809067), (1, 2, 3, 4, 0,  0.4207889 ),
       (1, 2, 3, 4, 0,  0.79489487), (1, 2, 3, 4, 0,  0.60212444),
       (1, 2, 3, 4, 0,  0.115112  ), (1, 2, 3, 4, 0,  0.61500626),
       (1, 2, 3, 4, 0,  0.42648162), (1, 2, 3, 4, 0,  0.49199412),
       (1, 2, 3, 4, 0,  0.37444409), (1, 2, 3, 4, 1,  0.8406318 ),
       (1, 2, 3, 4, 0,  0.92859289), (1, 2, 3, 4, 0,  0.1409527 ),
       (1, 2, 3, 4, 0,  0.82438293), (1, 2, 3, 4, 0,  0.95475589)],
      dtype=[('a', '<i8'), ('b', '<i8'), ('c', '<i8'), ('d', '<i8'), ('class', '<i8'), ('p', '<f8')])

我们可以根据结构数组的字段序列对其进行排序

In [93]: a = np.sort(a, order=('class','p',))

一班的记录,有多少

In [94]: b = a[a['class']==1]
In [95]: lb = len(b)

连接部分0类记录和b

In [100]: np.concatenate((a[a['class']==0][:lb], b))
Out[100]: 
array([(1, 2, 3, 4, 0,  0.04958431), (1, 2, 3, 4, 0,  0.115112  ), 
       (1, 2, 3, 4, 0,  0.1409527 ), (1, 2, 3, 4, 0,  0.37444409),
       (1, 2, 3, 4, 0,  0.4207889 ), (1, 2, 3, 4, 0,  0.42648162),
       (1, 2, 3, 4, 1,  0.15497822), (1, 2, 3, 4, 1,  0.16193617),
       (1, 2, 3, 4, 1,  0.25970286), (1, 2, 3, 4, 1,  0.29034866),
       (1, 2, 3, 4, 1,  0.40348877), (1, 2, 3, 4, 1,  0.75604181)],
      dtype=[('a', '<i8'), ('b', '<i8'), ('c', '<i8'), ('d', '<i8'), ('class', '<i8'), ('p', '<f8')])

您可以检查最后一个表达式的输出是否正是您所要求的。在


或者至少这是我认为你要求的。。。在

要使两个类具有相同数量的元素,可以从多数类中移除概率最高的元素,方法如下:

把你的矩阵叫做D,那么你的结果就是R

_, (max_count, min_count) = np.unique(D[:, 4], return_counts=True)
sort_cols = D[:, 4:]
flipped_cols = np.flip(sort_cols.T, axis=0)
S = D[np.lexsort(flipped_cols)]
S[:max_count, :] = np.flip(S[:max_count, :], axis=0)
R = S[min_count:, :]

解释

  1. 获取多数类和少数类样本数
    • 这一行依赖于这样一个假设:多数类被标记为0,少数类标记为1。根据你的需要调整这条线。在
  2. 获取排序期间要使用的列。在
  3. 将在np.词法排序. 在
  4. 这是最重要的一点。这一行首先根据label列对数据进行排序,然后根据probability列对数据进行排序。最后,你得到的是矩阵的上半部分是多数数据,下半部分是少数数据。这些部分本身是根据概率排序的。在
  5. 反转大多数部分的行,因为我们需要以最大的概率删除行。在
  6. 你可以让min_数多个多数行和所有少数行。这样,结果矩阵包含相同数量的多数和少数样本。在

参考文献

假设in[:, 4] = (in[:, 5] < t).astype(int),其中t是某个阈值值(可能是0.5):

n = np.sum(in[:, 4])                           # number of ones
i = np.argpartition(in[:, 5], 2 * n)[:2 * n]   # index of bottom 2n p values
out = in[i]                                    # or `np.sort(i)` to maintain original order

否则:

^{pr2}$

相关问题 更多 >

    热门问题