Obtenez des secondes valeurs minimales par colonne dans un tableau 2D


15

Comment puis-je obtenir la deuxième valeur minimale de chaque colonne? J'ai ce tableau:

A = [[72 76 44 62 81 31]
     [54 36 82 71 40 45]
     [63 59 84 36 34 51]
     [58 53 59 22 77 64]
     [35 77 60 76 57 44]]

Je souhaite avoir une sortie comme:

A = [54 53 59 36 40 44]

as-tu essayé quelque chose? ?
Meha Parekh

deuxième minimum par colonne ?
Nicolas Gervais

@NicolasGervais yes
Mr Dan

Réponses:


12

Essayez ceci, en une seule ligne:

[sorted(i)[1] for i in zip(*A)]

en action:

In [12]: A = [[72, 76, 44, 62, 81, 31], 
    ...:      [54 ,36 ,82 ,71 ,40, 45], 
    ...:      [63 ,59, 84, 36, 34 ,51], 
    ...:      [58, 53, 59, 22, 77 ,64], 
    ...:      [35 ,77, 60, 76, 57, 44]] 

In [18]: [sorted(i)[1] for i in zip(*A)]                                                                                                                                                                           
Out[18]: [54, 53, 59, 36, 40, 44]

zip(*A) transposera votre liste de liste afin que les colonnes deviennent des lignes.

et si vous avez une valeur en double, par exemple:

In [19]: A = [[72, 76, 44, 62, 81, 31], 
    ...:  [54 ,36 ,82 ,71 ,40, 45], 
    ...:  [63 ,59, 84, 36, 34 ,51], 
    ...:  [35, 53, 59, 22, 77 ,64],   # 35
    ...:  [35 ,77, 50, 76, 57, 44],]  # 35

Si vous devez ignorer les deux 35, vous pouvez utiliser set():

In [29]: [sorted(list(set(i)))[1] for i in zip(*A)]                                                                                                                                                                
Out[29]: [54, 53, 50, 36, 40, 44]

6

Les opérations sur les numpytableaux doivent être effectuées avec des numpyfonctions, alors regardez celle-ci:

np.sort(A, axis=0)[1, :]
Out[61]: array([54, 53, 59, 36, 40, 44])

Ce doit être la meilleure solution pour autant que je sache, elle garde tout en place numpy, je pense que la solution lambdadoit ralentir heapq.nsmallest. Il semble préférable de tout garder rapidenumpy
jamylak

3

vous pouvez utiliser heapq.nsmallest

from heapq import nsmallest

[nsmallest(2, e)[-1] for e in zip(*A)]

production:

[54, 53, 50, 36, 40, 44]

J'ai ajouté un benchmark simple pour comparer les performances des différentes solutions déjà publiées:

entrez la description de l'image ici

from simple_benchmark import BenchmarkBuilder
from heapq import nsmallest


b = BenchmarkBuilder()

@b.add_function()
def MehrdadPedramfar(A):
    return [sorted(i)[1] for i in zip(*A)]

@b.add_function()
def NicolasGervais(A):
    return np.sort(A, axis=0)[1, :]

@b.add_function()
def imcrazeegamerr(A):
    rotated = zip(*A[::-1])

    result = []
    for arr in rotated:
        # sort each 1d array from min to max
        arr = sorted(list(arr))
        # add the second minimum value to result array
        result.append(arr[1])

    return result

@b.add_function()
def Daweo(A):
    return np.apply_along_axis(lambda x:heapq.nsmallest(2,x)[-1], 0, A)

@b.add_function()       
def kederrac(A):
    return [nsmallest(2, e)[-1] for e in zip(*A)]


@b.add_arguments('Number of row/cols (A is  square matrix)')
def argument_provider():
    for exp in range(2, 18):
        size = 2**exp
        yield size, [[randint(0, 1000) for _ in range(size)] for _ in range(size)]

r = b.run()
r.plot()

Utiliser zipavec la sortedfonction est la solution la plus rapide pour les petites listes 2D tout en utilisant zipavec les heapq.nsmallestémissions pour être le meilleur sur les grandes listes 2D


1
Juste une pensée sauvage: ces résultats peuvent-ils être affectés par le fait que vous avez généré des nombres qui ne sont pas des dtypes numpy? De plus, le randint intégré ne retournera-t-il pas une liste au lieu d'un tableau?
Nicolas Gervais

1

J'espère avoir bien compris votre question, mais dans tous les cas, voici ma solution, je suis sûr qu'il existe une façon plus élégante de le faire, mais cela fonctionne

A = [[72,76,44,62,81,31]
 ,[54,36,82,71,40,45]
 ,[63,59,84,36,34,51]
 ,[58,53,59,22,77,64]
 ,[35,77,50,76,57,44]]

#rotate the array 90deg
rotated = zip(*A[::-1])

result = []
for arr in rotated:
    # sort each 1d array from min to max
    arr = sorted(list(arr))
    # add the second minimum value to result array
    result.append(arr[1])
print(result)

entrez la description de l'image ici


0

En supposant que ce Asoit le numpy.arraycas (si cela se vérifie, envisagez d'ajouter une numpybalise à votre question), vous pouvez utiliser la apply_along_axisméthode suivante:

import heap
import numpy as np
A = np.array([[72, 76, 44, 62, 81, 31],
              [54, 36, 82, 71, 40, 45],
              [63, 59, 84, 36, 34, 51],
              [58, 53, 59, 22, 77, 64],
              [35, 77, 60, 76, 57, 44]])
second_mins = np.apply_along_axis(lambda x:heapq.nsmallest(2,x)[-1], 0, A)
print(second_mins)  # [54 53 59 36 40 44]

Notez que j'ai utilisé heapq.nsmallest car il fait autant de tri que nécessaire pour obtenir 2 plus petits éléments, contrairement à sortedce qui fait le tri complet.


0
>>> A = np.arange(30).reshape(5,6).tolist()
>>> A
[[0, 1, 2, 3, 4, 5], 
 [6, 7, 8, 9, 10, 11], 
 [12, 13, 14, 15, 16, 17], 
 [18, 19, 20, 21, 22, 23],
 [24, 25, 26, 27, 28, 29]]

Mise à jour : utiliser setpour empêcher la duplication et la transposition de la liste à l'aidezip(*A)

>>> [sorted(set(items))[1] for items in zip(*A)]
[6, 7, 8, 9, 10, 11]

ancien: deuxième élément minimum dans chaque ligne

>>> [sorted(set(items))[1] for items in A]
[1, 7, 13, 19, 25]

N'est-ce pas obtenir le deuxième élément de chaque ligne plutôt que colonne?
paxdiablo

@paxdiablo Oui merci pour l'informer. réponse mise à jour.
Dishin H Goyani
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.