У меня есть прямоугольная матрица с n строками и m столбцом. Все элементы матрицы — натуральные числа (включая 0).
Среди m столбцов мне присвоен некоторый индекс j (< m). Я бы хотел, чтобы матрица стала блочной матрицей, как показано ниже.
Для первых i строк (мы можем выбрать любой i <= n, какой хотим) каждая запись справа от j должна быть равна 0. А для следующих (n-i) строк каждая запись слева от индекса j (включая j ) должно быть 0.
Если это невозможно, сумма записей в двух заштрихованных областях (темно-серого цвета) на рисунке выше должна быть как можно меньше.
Единственные операции, разрешенные с исходной матрицей, — это замена строк и столбцов. Меня интересует эффективный алгоритм для достижения этой цели.
Вот CSV-файл исходной матрицы (реальные данные из моего приложения): https://github.com/ryu577/optimizn/blob/master/optimizn/ab_split/testing/arrs_orig.csv
Дж — 25.
Я набрал 561 балл по этой матрице с имитацией отжига. Мне было бы интересно посмотреть, сможет ли кто-нибудь победить это.
Но M1 и M2 не обязательно должны быть сильно связными матрицами смежности компонентов.
Кроме того, матрица прямоугольная.
Вы можете рассматривать его как двудольный график, он работает по сути одинаково.
Первый проход должен заключаться в подсчете количества нулей в каждой строке, что ограничивает значение j и немедленно сообщает вам, невозможна ли ваша целевая форма блока. Вы можете сделать то же самое (менее эффективно) для каждого столбца, который таким же образом ограничивает k. Сортировка строк по количеству нулей в них кажется разумным способом продолжить работу после этого. Замена колонок обойдется дороже, поэтому чем их меньше, тем лучше.
Если M1 и M2 полностью ненулевые, то количество нулей в каждой строке и столбце будет одинаковым. Возможно, это крайний случай. А если мы транспонируем матрицу до замены столбцов, они тоже станут дешевыми, не так ли?
Хотя я обычно не одобряю комментарии, выражающие лишь догадки, я рискну и предположу, что это может быть хорошо изученная проблема в линейной алгебре.
Неясно, задан ли i
или это результат работы алгоритма.
(@Оливье Not clear whether i is given or [an output]
we can choose any i <= n we want
)
@RohitPandey Что означает оценка (561)?
Это означает, что если я просуммирую столбцы в двух серых областях, я получу 561.
@RohitPandey Мой код, слегка измененный, чтобы предотвратить бесконечный цикл сортировки разреженной матрицы, дает минимум 30 при i=49 и j=166.
@SudoKoach - извините, я должен был уточнить здесь ... j фиксирован на 25. Мы можем перемещать i, но не можем перемещать j (вопрос проясняет это).
Это проблема минимального разреза с ограничением по размеру. Это NP-трудно решить точно.
Поскольку вы задали вопрос с точки зрения матриц, я рискну и предположу, что у вас есть свободный доступ к библиотеке, которая может вычислить частичное разложение по сингулярным значениям. Если да, то позвольте мне предложить дешевую спектральную эвристику.
Найдите сингулярный вектор m
-элемента, соответствующий наибольшему сингулярному значению. Предполагая, что элементы этого вектора различны (без потери общности из-за возмущения или использования индексов для разрыва связей), выберите элемент порядка j
; элементы с меньшими значениями соответствуют первым j-1
столбцам выходных данных, а элементы с большими значениями соответствуют последним m-j
столбцам. При таком расположении столбцов каждая строка «голосует» за то, должна ли она находиться в верхней или нижней половине.
Спасибо. Разве это не то же самое, что сортировать столбцы по элементам наибольшего сингулярного вектора? Почему это сработает? И сработает ли голосование среди рядов?
@RohitPandey да, ты можешь сортировать.
Извините, я хотел спросить... как будет проходить голосование среди рядов? Может быть, отсортировать по суммам до j?
@RohitPandey, да! Signum([сумма до j] - [сумма после j])
j задан... это все еще актуально?
@quester Ключевым моментом здесь является то, что во время голосования мы выбираем порядок столбцов.
Не могли бы вы объяснить, почему порядок элементов наибольшего сингулярного вектора можно использовать таким образом?
@RohitPandey этот предмет не является моей специальностью, моя интуиция довольно проста, но если бы M_1 и M_2 были бы единицами, то было бы две пары сингулярных векторов: первая пара имела бы один вектор, поддерживаемый в первых j столбцах, и один вектор поддерживается в первых i строках; вторая пара будет иметь один вектор, поддерживаемый в других столбцах, и один вектор, поддерживаемый в других строках. SVD безразличен к перестановкам строк и столбцов, поэтому способен восстанавливать структуру.
Вот решение «старой школы» для уточнения требований и сравнительного анализа. Если разрешены только операции «перестановка строк и замена столбцов», то матрицу можно разделить только с сортировкой по строкам и по столбцам. Строки сортируются по возрастанию соответствующих столбцов средневзвешенного значения. Столбцы отсортированы по возрастанию соответствующих строк средневзвешенного значения.
import numpy as np
rng = np.random.default_rng()
N=7
M=15
nbmax=min(N,M)-4
A = rng.integers(0, 4, (N,M))
def getWACols(A,N,M):
wacols=[]
colsom=np.sum(A,axis=1)
for row in range(N):
wsum=0
for col in range(M):
wsum+=A[row,col]*col
if colsom[row]!=0 :
wacols.append(wsum/colsom[row])
else:
wacols.append((M-1)/2)
return np.array(wacols)
def getWARows(A,N,M):
warows=[]
rowsom=np.sum(A,axis=0)
for col in range(M):
wsum=0
for row in range(N):
wsum+=A[row,col]*row
if rowsom[col]!=0:
warows.append(wsum/rowsom[col])
else:
warows.append((N-1)/2)
return np.array(warows)
def sortByRow(A,N,M):
B=np.zeros((N,M),np.int32)
wacols_sorted=np.argsort(getWACols(A,N,M))
bn=True
for row in range(N):
for col in range(M):
B[row,col]=A[wacols_sorted[row],col]
bn=bn and row==wacols_sorted[row]
return B,bn
def sortByCol(A,N,M):
B=np.zeros((N,M),np.int32)
warows_sorted=np.argsort(getWARows(A,N,M))
bn=True
for col in range(M):
for row in range(N):
B[row,col]=A[row,warows_sorted[col]]
bn=bn and col==warows_sorted[col]
return B,bn
def partitionMatrix(A,N,M):
B,bn=sortByRow(A,N,M)
bn1=bn and True
B,bn=sortByCol(B,N,M)
return B,bn and bn1
print(A)
B=np.copy(A)
bn=False
cntr=0
while not bn and cntr<100:
B,bn=partitionMatrix(B,N,M)
cntr+=1
print(B)
j=np.sum(getWACols(B,N,M))/M
i=np.sum(getWARows(B,N,M))/N
print(i,j)
Спасибо за решение. Я попробовал это в своем тестовом примере, и, похоже, это не лучшее мое решение. Но я включил в вопрос тестовый пример на случай, если вы захотите подтвердить.
Два практических подхода:
Ни один из них не гарантирует оптимального решения.
Спасибо! Не понял, как добавить регуляризатор для преобразования матриц в правильную перестановку?
Добавьте в целевую функцию термин, который будет отдавать предпочтение нулям и единицам в R и C. Например, α|(x-0,5)²-0,25|, где x — каждый коэффициент R и C, а α постепенно увеличивается в вашей целевой функции. итеративный оптимизатор, каким бы он ни был.
Если рассматривать матрицу как матрицу смежности графа, то блоки соответствуют связным компонентам. Для их поиска существуют эффективные алгоритмы.