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

时间:2017-10-29 08:23:17

标签: python arrays numpy scipy

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

看起来像这样:

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

前4个值是参数,第五个是类,第六个是0类概率。

问题是,数据是强烈极化的 - 类0的行数比使用类1的行多20倍。这对于学习是不好的,我需要删除0级的许多行。但是,为了获得最佳结果,我不想随意删除数据,但是像这样:

我需要在循环中删除索引5(类0的概率)上具有最高值的行,因为在索引4(类)中有0和1的行数相同。

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

这有点复杂,所以如果你有更多问题,请随时提问。

3 个答案:

答案 0 :(得分:0)

通过从多数类中删除具有最高概率的元素来使两个类具有相同数量的元素,可以按如下方式完成:

调用矩阵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. flipped_cols将用于np.lexsort。
  4. 这是重要的一点。此行首先根据标签列对数据进行排序,然后根据概率列对数据进行排序。最后,你得到的是在矩阵的上半部分你有大多数数据,在下半部分你有少数数据。这些部分本身就概率进行了分类。
  5. 反转大多数部分行,因为我们需要删除概率最高的行。
  6. 你得到min_count许多多数行和所有少数行。通过这种方式,您的结果矩阵包含相同数量的多数和少数样本。
  7. 参考

答案 1 :(得分:0)

假设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

否则:

nz  = np.flatnonzero(in[:, 4])         # boolean index of `1` rows
z   = np.flatnonzero(in[:, 4] == 0)    # boolean index of `0` rows
n   = nz.size                          # same as above
i   = np.argpartition(in[z, 5], n)[:n] # bottom n p values from `0`
j   = np.sort(np.r_[z[i], nz])         # combine `1` indices and bottom n `0` indices
out = in[j]                            # output

答案 2 :(得分:0)

让我们生成一些假数据

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行,因此我们(可能)有一个优势零。

In [87]: for row in data: row[4] = 0 if row[4]==2 else row[4]

在你的例子中你使用了一个结构化数组,所以我也有一个结构化数组...要创建一个结构化数组,我们需要一个元组列表,而不是列表列表

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',))

第1课的记录,其中有多少

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')])

您可以检查最后一个表达式的输出是否与您要求的完全相同。

PS或至少是我认为你要求的......