Home > Blockchain >  Finding the "loser" in Each Row
Finding the "loser" in Each Row

Time:06-10

I have this dataset ("m"):

structure(list(id = 1:4, A1 = c(20, 20, 20, 20), B1 = c(20, 20, 
20, 20), A2 = c(19.638362385164, 8.11972427580967, 11.9810539199604, 
11.179853022028), B2 = c(15.974094766586, 11.02249487622, 14.2062464923062, 
9.6806947619966), A3 = c(1.41008362674648, 2.36347304689385, 
5.89401239396941, 10.2478961230446), B3 = c(3.43887450489555, 
8.70503533284162, 6.31828253609099, -3.40081750462382), A4 = c(0.021848581788209, 
-0.946584014278003, -22.2024625188847, NA), B4 = c(-5.73617894284438, 
1.6375826801224, 3.8312939605301, NA)), row.names = c(1L, 5L, 
9L, 13L), class = "data.frame", reshapeWide = list(v.names = NULL, 
    timevar = "time", idvar = "id", times = 1:4, varying = structure(c("A1", 
    "B1", "A2", "B2", "A3", "B3", "A4", "B4"), .Dim = c(2L, 4L
    ))))

   id A1 B1        A2        B2        A3        B3           A4        B4
1   1 20 20 19.638362 15.974095  1.410084  3.438875   0.02184858 -5.736179
5   2 20 20  8.119724 11.022495  2.363473  8.705035  -0.94658401  1.637583
9   3 20 20 11.981054 14.206246  5.894012  6.318283 -22.20246252  3.831294
13  4 20 20 11.179853  9.680695 10.247896 -3.400818           NA        NA

I would like to add a column to this dataset that contains the "loser" of each row - by this I mean, whether variable "A" or variable "B" contains the lowest value. The final product would look something like this:

   id A1 B1        A2        B2        A3        B3           A4        B4    loser
1   1 20 20 19.638362 15.974095  1.410084  3.438875   0.02184858 -5.736179 Player B
5   2 20 20  8.119724 11.022495  2.363473  8.705035  -0.94658401  1.637583 Player A
9   3 20 20 11.981054 14.206246  5.894012  6.318283 -22.20246252  3.831294 Player A
13  4 20 20 11.179853  9.680695 10.247896 -3.400818           NA        NA Player B

I tried to solve this problem in an indirect way - for each row, find the column number that corresponds to the smallest element. If the column number is "odd", then loser = Player B - else loser = Player A.

I tried to do this using the following codes:

 l = apply( m, 1, which.min)
 1  5  9 13 
 9  8  8  7 

    m$l = l
> ifelse(m$l %% 2 == 0,  "Player A", "Player B" )
[1] "Player B" "Player A" "Player A" "Player B"
> loser = ifelse(m$l %% 2 == 0,  "Player A", "Player B" )
> loser
[1] "Player B" "Player A" "Player A" "Player B"
> m$loser = loser
> m
   id A1 B1        A2        B2        A3        B3           A4        B4 l    loser
1   1 20 20 19.638362 15.974095  1.410084  3.438875   0.02184858 -5.736179 9 Player B
5   2 20 20  8.119724 11.022495  2.363473  8.705035  -0.94658401  1.637583 8 Player A
9   3 20 20 11.981054 14.206246  5.894012  6.318283 -22.20246252  3.831294 8 Player A
13  4 20 20 11.179853  9.680695 10.247896 -3.400818           NA        NA 7 Player B
  • Have I done this correctly? Is my logic correct?

Thank you!

CodePudding user response:

We can use pmap to help pull the name of the column that has the minimum value. So, all columns are put into c(...) to find the minimum value, then we subset using names. We can then just extract only the letter and paste to "Player" to get the desired output for loser. You could do all of that in one step, but I decided to put it as a second mutate line for readability.

library(tidyverse)

m %>%
  mutate(loser = pmap(across(-id), ~ names(c(...)[which.min(c(...))])),
         loser = str_c("Player ", str_extract(loser, "[[:alpha:]]")))

Output

   id A1 B1        A2        B2        A3        B3           A4        B4    loser
1   1 20 20 19.638362 15.974095  1.410084  3.438875   0.02184858 -5.736179 Player B
5   2 20 20  8.119724 11.022495  2.363473  8.705035  -0.94658401  1.637583 Player A
9   3 20 20 11.981054 14.206246  5.894012  6.318283 -22.20246252  3.831294 Player A
13  4 20 20 11.179853  9.680695 10.247896 -3.400818           NA        NA Player B

Or another tidyverse option:

m %>%
  rowwise() %>%
  mutate(loser = names(.)[-1][which.min(c_across(cols = -c(id)))],
         loser = str_c("Player ", str_extract(loser, "[[:alpha:]]")))

CodePudding user response:

Using Base R:

m$loser <- sub("\\d ", '', names(m[-1])[max.col(-replace(m[-1], is.na(m[-1]),0))])

  id A1 B1        A2        B2        A3        B3           A4        B4 loser
1   1 20 20 19.638362 15.974095  1.410084  3.438875   0.02184858 -5.736179     B
5   2 20 20  8.119724 11.022495  2.363473  8.705035  -0.94658401  1.637583     A
9   3 20 20 11.981054 14.206246  5.894012  6.318283 -22.20246252  3.831294     A
13  4 20 20 11.179853  9.680695 10.247896 -3.400818           NA        NA     B
  •  Tags:  
  • r
  • Related