Nick
Nick

Reputation: 1116

How to write condition on minimal elements?

I have a symmetric matrix with zero diagonal elements:

set.seed(42)

m<-matrix(runif(25),5)
m[lower.tri(m)] = t(m)[lower.tri(m)]

diag(m)<-0
m


         [,1]      [,2]      [,3]      [,4]      [,5]
[1,] 0.0000000 0.5190959 0.4577418 0.9400145 0.9040314
[2,] 0.5190959 0.0000000 0.7191123 0.9782264 0.1387102
[3,] 0.4577418 0.7191123 0.0000000 0.1174874 0.9888917
[4,] 0.9400145 0.9782264 0.1174874 0.0000000 0.9466682
[5,] 0.9040314 0.1387102 0.9888917 0.9466682 0.0000000

I need to put -1 to all the elements below diagonal except the the minimum element in each column:

Expected result is:

         [,1]      [,2]      [,3]      [,4]      [,5]
[1,]  0.0000000 -1.0000000  -1.0000000 -1.0000000 -1.0000000
[2,] -1.0000000  0.0000000 -1.0000000 -1.0000000  -1.0000000
[3,]  0.4577418  -1.0000000  0.0000000  -1.0000000 -1.0000000
[4,] -1.0000000 -1.0000000  0.1174874  0.0000000  -1.0000000
[5,] -1.0000000  0.1387102 -1.0000000  0.9466682  0.0000000

My attemp is:

for (i in 2:ncol(m)) 
#if (m[,i] > 0) 
x <- pmin(x, m[,i])
x


min = which(m == min(m), arr.ind = TRUE)  
min

Question. How to add condition on diagonal elements?

Upvotes: 1

Views: 47

Answers (2)

Iroha
Iroha

Reputation: 34751

You can do:

m[!sweep(m, 2, apply(replace(m, upper.tri(m, diag = TRUE), Inf), 2, min), `==`)] <- -1

`diag<-`(m, 0)

       [,1]       [,2]       [,3]       [,4] [,5]
[1,]  0.0000000 -1.0000000 -1.0000000 -1.0000000   -1
[2,] -1.0000000  0.0000000 -1.0000000 -1.0000000   -1
[3,]  0.4577418 -1.0000000  0.0000000 -1.0000000   -1
[4,] -1.0000000 -1.0000000  0.1174874  0.0000000   -1
[5,] -1.0000000  0.1387102 -1.0000000  0.9466682    0

Upvotes: 1

Roman
Roman

Reputation: 17678

You can try this...but I'm pretty sure that there is an easier way.

m_tmp <- m
m_tmp[upper.tri(m, diag = T)] <- NA

library(tidyverse)
m_tmp %>% 
  as.data.frame() %>% 
  rowid_to_column() %>% 
  pivot_longer(-1) %>% 
  group_by(name) %>% 
  mutate(val = sum(is.na(value))) %>%
  mutate(value = ifelse(val == 5, -1, value)) %>%
  mutate(value = ifelse(value == min(value, na.rm = T), value, -1)) %>%
  select(-val) %>% 
  filter(!is.na(value)) %>% 
  pivot_wider(names_from = "name", values_from = "value", values_fill = -1)  %>% 
  select(-1) %>% 
  as.matrix()
             V1         V2         V3         V4 V5
[1,]  0.0000000 -1.0000000 -1.0000000 -1.0000000 -1
[2,] -1.0000000  0.0000000 -1.0000000 -1.0000000 -1
[3,]  0.4577418 -1.0000000  0.0000000 -1.0000000 -1
[4,] -1.0000000 -1.0000000  0.1174874  0.0000000 -1
[5,] -1.0000000  0.1387102 -1.0000000  0.9466682  0

Upvotes: 1

Related Questions