Obtenga los segundos valores mínimos por columna en la matriz 2D

15

¿Cómo puedo obtener el segundo valor mínimo de cada columna? Tengo esta matriz:

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

Deseo tener resultados como:

A = [54 53 59 36 40 44]
Señor dan
fuente
has intentado algo? ?
Meha Parekh
segundo mínimo por columna ?
Nicolas Gervais
@NicolasGervais sí
Sr. Dan

Respuestas:

12

Prueba esto, en una sola línea:

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

en acción:

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) transpondrá su lista de listas para que las columnas se conviertan en filas.

y si tiene un valor duplicado, por ejemplo:

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 necesita omitir ambos 35, puede usar set():

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

Las operaciones en numpymatrices deben realizarse con numpyfunciones, así que mira esta:

np.sort(A, axis=0)[1, :]
Out[61]: array([54, 53, 59, 36, 40, 44])
Nicolas Gervais
fuente
Por lo que sé, esta tiene que ser la mejor solución, mantiene todo dentro numpy, creo que la solución lambdadebe disminuir la velocidad heapq.nsmallest. Parece mejor mantener todo rápidonumpy
jamylak
3

puedes usar heapq.nsmallest

from heapq import nsmallest

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

salida:

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

Agregué un punto de referencia simple para comparar el rendimiento de las diferentes soluciones ya publicadas:

ingrese la descripción de la imagen aquí

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()

Usar zipcon la sortedfunción es la solución más rápida para listas 2d pequeñas mientras se usa zipcon heapq.nsmallestespectáculos para ser el mejor en listas 2d grandes

Kederrac
fuente
1
Solo un pensamiento descabellado: ¿pueden verse afectados estos resultados por el hecho de que generó números que no son tipos vacíos? Además, ¿el randint incorporado no devolverá una lista en lugar de una matriz?
Nicolas Gervais
1

Espero haber entendido su pregunta correctamente, pero de cualquier manera esta es mi solución, estoy seguro de que hay una forma más elegante de hacerlo, pero funciona

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)

ingrese la descripción de la imagen aquí

imcrazeegamer
fuente
0

Suponiendo que Aes así numpy.array(si esto es cierto, considere agregar una numpyetiqueta a su pregunta), entonces puede usarlo apply_along_axisde la siguiente manera:

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]

Tenga en cuenta que usé heapq.nsmallest, ya que realiza la clasificación necesaria para obtener 2 elementos más pequeños, a diferencia de lo sortedque hace la ordenación completa.

Daweo
fuente
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]]

Actualizado : Use setpara evitar duplicar y transponer la lista usandozip(*A)

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

antiguo: segundo elemento mínimo en cada fila

>>> [sorted(set(items))[1] for items in A]
[1, 7, 13, 19, 25]
Dishin H Goyani
fuente
¿No es eso obtener el segundo elemento en cada fila en lugar de columna?
paxdiablo
@paxdiablo Sí, gracias por informar. respuesta actualizada
Dishin H Goyani