как получить своего рода «максимум» в матрице, эффективно - PullRequest
3 голосов
/ 07 марта 2019

У меня следующая проблема: у меня есть матрица, открытая с модулем pandas, где каждая ячейка имеет число от -1 до 1. То, что я хотел найти, - это максимальное "возможное" значение в строке, которое такжене максимальное значение в другом ряду.

Если, например, в одном столбце максимальное значение имеет, например, 2 строки, я сравниваю оба значения и беру большее значение, а затем для строки, максимальное значение которой меньше, чем в другой строке, я взял второй максимумзначение (и повторять один и тот же анализ снова и снова).

Чтобы объяснить себя, лучше рассмотрите мой код

import pandas as pd

matrix = pd.read_csv("matrix.csv") 
# this matrix has an id (or name) for each column 
# ... and the firt column has the id of each row
results = pd.DataFrame(np.empty((len(matrix),3),dtype=pd.Timestamp),columns=['id1','id2','max_pos'])

l = len(matrix.col[[0]]) # number of columns

while next = 1:
   next = 0
   for i in range(0, len(matrix)):
       max_column = str(0)
       for j in range(1, l): # 1 because the first column is an id
           if matrix[max_column][i] < matrix[str(j)][i]:
               max_column = str(j)
       results['id1'][i] = str(i) # I coul put here also matrix['0'][i]
       results['id2'][i] = max_column
       results['max_pos'][i] = matrix[max_column][i]

   for i in range(0, len(results)): #now I will check if two or more rows have the same max column
       for ii in range(0, len(results)):
       # if two id1 has their max in the same column, I keep it with the biggest 
       # ... max value and chage the other to "-1" to iterate again
           if (results['id2'][i] == results['id2'][ii]) and (results['max_pos'][i] < results['max_pos'][ii]):
               matrix[results['id2'][i]][i] = -1
               next = 1

Пример:

#consider
pd.DataFrame({'a':[1, 2, 5, 0], 'b':[4, 5, 1, 0], 'c':[3, 3, 4, 2], 'd':[1, 0, 0, 1]})

   a  b  c  d
0  1  4  3  1
1  2  5  3  0
2  5  1  4  0
3  0  0  2  1

#at the first iterarion I will have the following result

0  b  4 # this means that the row 0 has its maximum at column 'b' and its value is 4
1  b  5
2  a  5
3  c  2

#the problem is that column b is the maximum of row 0 and 1, but I know that the maximum of row 1 is bigger than row 0, so I take the second maximum of row 0, then:

0  c  3
1  b  5
2  a  5
3  c  2

#now I solved the problem for row 0 and 1, but I have that the column c is the maximum of row 0 and 3, so I compare them and take the second maximum in row 3 

0  c  3
1  b  5
2  a  5
3  d  1

#now I'm done. In the case that two rows have the same column as maximum and also the same number, nothing happens and I keep with that values.

#what if the matrix would be 
pd.DataFrame({'a':[1, 2, 5, 0], 'b':[5, 5, 1, 0], 'c':[3, 3, 4, 2], 'd':[1, 0, 0, 1]})

   a  b  c  d
0  1  5  3  1
1  2  5  3  0
2  5  1  4  0
3  0  0  2  1

#then, at the first itetarion the result will be:

0  b  5
1  b  5
2  a  5
3  c  2

#then, given that the max value of row 0 and 1 is at the same column, I should compare the maximum values
# ... but in this case the values are the same (both are 5), this would be the end of iterating 
# ... because I can't choose between row 0 and 1 and the other rows have their maximum at different columns...

Этот код работаетидеально подходит для меня, если у меня есть матрица 100x100, например.Но, если размер матрицы достигает 50 000 x 50 000, код занимает много времени для его завершения.Я теперь, что мой код может быть самым неэффективным способом сделать это, но я не знаю, как с этим справиться.

Я читал о потоках в Python, которые могут помочь, но это не поможет, если я добавлю 50 000 потоков, потому что мой компьютер не использует больше ЦП.Я также пытался использовать некоторые функции как .max(), но я не могу получить столбец максимума и сравнить его с другим максимумом ...

Если кто-нибудь может помочь мне дать мне кусоксовет, чтобы сделать это более эффективным, я был бы очень признателен.

1 Ответ

1 голос
/ 07 марта 2019

Будет нужно больше информации об этом. Чего ты здесь пытаешься достичь?

Это поможет вам разобраться, но для полного достижения того, что вы делаете, мне нужно больше контекста.

Мы импортируем numy, random и Counter из коллекций:

import numpy as np
import random 
from collections import Counter

Мы создадим случайную матрицу чисел 50k x 50k между -10M и + 10M

mat = np.random.randint(-10000000,10000000,(50000,50000))

Теперь, чтобы получить максимумы для каждой строки , мы можем просто сделать следующее понимание списка:

maximums = [max(mat[x,:]) for x in range(len(mat))]

Теперь мы хотим выяснить, какие из них не являются максимумами в каких-либо других строках. Мы можем использовать Counter в нашем списке максимумов, чтобы узнать, сколько из них есть. Счетчик возвращает объект счетчика, который похож на словарь с максимумом в качестве ключа, и количество раз, которое он появляется в качестве значения. Затем мы понимаем словарь, где значение равно от == до 1. Это даст нам максимумы, которые появляются только один раз. мы используем функцию .keys() для захвата самих чисел, а затем превращаем их в список.

c = Counter(maximums)
{9999117: 15,
9998584: 2,
9998352: 2,
9999226: 22,
9999697: 59,
9999534: 32,
9998775: 8,
9999288: 18,
9998956: 9,
9998119: 1,
...}

k = list( {x: c[x] for x in c if c[x] == 1}.keys() )

[9998253,
 9998139,
 9998091,
 9997788,
 9998166,
 9998552,
 9997711,
 9998230,
 9998000,
...]

Наконец, мы можем сделать следующее понимание списка, чтобы перебрать исходный список максимумов, чтобы получить указание того, где находятся эти строки.

indices = [i for i, x in enumerate(maximums) if x in k]

В зависимости от того, что еще вы хотите сделать, мы можем пойти отсюда.

Это не самая быстрая программа, но поиск максимумов, счетчика и индикаторов занимает 182 секунды на уже загруженной матрице 50 000 на 50 000.

...