根据数组的另一列在一列中汇总最小值最大值-Python

时间:2019-11-18 04:15:38

标签: python python-3.x numpy

如果它们具有相同的索引,我试图将它们连接起来。我正在处理矩形,所以我知道:

  • 总是至少有两个相同的索引。
  • 如果索引超过2个,我只需要存储最大值和最小值。

基本上

发件人:

a = array([
       [ 1,  5],
       [ 1,  7],
       [ 2,  8],
       [ 2, 10],
       [ 2, 22],
       [ 3, 55],
       [ 3, 77]])

收件人:

b = np.array([
       [ 1, 5, 7],
       [ 2, 8, 22], # [2,8,10,22] but the min is 8 and max is 22
       [ 3, 55, 77]])

我试图将其转换为列表,并使用for循环遍历每个值,但这需要花费大量时间。

我还尝试对数组np.sort(a, axis=0)进行排序,并每隔一行取一列,但是由于可以有两个以上的索引,因此失败。

我是numpy的新手,所以不知道还能尝试什么。

任何和所有建议都会有所帮助,谢谢。

编辑:其行为类似于字典,其中键为a [0],值为a [1:]

如果有两个以上的值,我只会保留最小值和最大值。

4 个答案:

答案 0 :(得分:2)

使用pandas

的方法
import pandas as pd
# create a dataframe with 2 columns corresponding to the columns of a
df = pd.DataFrame({ 'indices':a[:,0],'values':a[:,1]}) 
# compute min and max by indices
df2 = df.groupby('indices').agg({'values': ['min', 'max']}).reset_index()
# convert to numpy array
np.asarray(df2)
#array([[ 1,  5,  7],
#       [ 2,  8, 22],
#       [ 3, 55, 77]], dtype=int64)

答案 1 :(得分:2)

使用numpy的方法, 您可以使用numpy.split根据第一个轴上的值将它们拆分为独立的数组。然后您可以找到最小和最大。

有关拆分及其工作方式的更多信息, 您可以查看答案here。我在这里不再重复。

ar = np.split(a, np.flatnonzero(a[1:,0] != a[:-1,0])+1,axis=0)

上面的行拆分并生成轴0上每个唯一值的数组列表。

上面的行将产生类似

的输出
[
array([[1, 5],
       [1, 7]]),
array([[ 2,  8],
       [ 2, 10],
       [ 2, 22]]), 
array([[ 3, 55],
       [ 3, 77]])
]

然后,您可以迭代它们以在输出中找到期望的列表的性质。

final_list = []
for i in ar:
  final_list.append([i[1][0],np.min(i[:,1]),np.max(i[:,1])])
print(final_list)

上面的代码将产生类似

的输出
[[1, 5, 7], [2, 8, 22], [3, 55, 77]]

答案 2 :(得分:1)

方法1

矢量化的NumPy方法是-

def agg_minmax(a):
    sidx = np.lexsort(a[:,::-1].T)
    b = a[sidx]
    m = np.r_[True,b[:-1,0]!=b[1:,0],True]
    return np.c_[b[m[:-1],:2], b[m[1:],1]]

样品运行-

# Generic case with input not-necessarily sorted by first col
In [35]: a
Out[35]: 
array([[ 3, 77],
       [ 2,  8],
       [ 1,  7],
       [ 2, 10],
       [ 1,  5],
       [ 3, 55],
       [ 2, 22]])

In [36]: agg_minmax(a)
Out[36]: 
array([[ 1,  5,  7],
       [ 2,  8, 22],
       [ 3, 55, 77]])

方法2

我们可以改善内存,以便仅按sidx对第一行进行排序,就像这样-

def agg_minmax_v2(a):
    sidx = np.lexsort(a[:,::-1].T)
    b = a[sidx,0]
    m = np.r_[True,b[:-1]!=b[1:],True]
    return np.c_[a[sidx[m[:-1]]],a[sidx[m[1:]],1]]

如果每个组有很多条目,这可能会更好。


替代方法1:使用线性索引映射获取sidx

对于正整数值,我们可以假定它们在2D网格上,因此可以得到每行的线性索引等效项。因此,我们将跳过lexsort并得到sidx-

sidx = (a[:,0]*(a[:,1].max()+1) + a[:,1]).argsort()

在两种较早发布的方法中,获得sidx后的其余代码保持不变。

替代方法2:使用sidx

获取views

我们可以使用views来获取sidx,因此再次跳过lexsort,就像这样-

# https://stackoverflow.com/a/44999009/ @Divakar
def view1D(a): # a is array
    a = np.ascontiguousarray(a)
    void_dt = np.dtype((np.void, a.dtype.itemsize * a.shape[1]))
    return a.view(void_dt).ravel()

A = view1D(a)
sidx = A.argsort()

答案 3 :(得分:0)

一种这样做的方法(不太好)是使用普通列表。

# convert to list and sort if not already sorted
alist = a.tolist()
alist.sort()

# initial values for looping
currval = alist[0][0]
min     = alist[0][1]
max     = alist[0][1]

# new list to store results in
result = []

# loop through all rows of alist
for row in alist:
    if currval == row[0]: # still same index
        max = row[1]   # update max
    else:
        result.append([currval, min, max]) # save row
        currval = row[0] # update to next index
        min     = row[1]
        max     = row[1]

# save last row
result.append([currval, min, max]) # save row
currval = row[0] # update to next index
min     = row[1]
max     = row[1]

# convert output to nparray
b = np.array(result)

它利用Python在列表上的sort行为,通过对具有相同索引的值进行分组并将值按升序排列,从而很好地对列表进行排序。