Easier function to find elements bigger than a number in each column in R

Viewed 35

I am a beginner at R and I am trying to learn mostly on my own. I have found some exercises and it was given a data frame and asked to find the student that had 3 grades smaller than 8.

df <- data.frame(Name = c('Ana', 'John', 'Joanna', 'Anna', 'Martin', 'Katrin'), 
                 Age = c(24, 26, 26, 31, 32, 45),
                 Height = c(1.7, 1.82, 1.75, 31, 32, 45), 
                 Gender = c('M', 'M','F', 'F', 'M','F'),
                 stringsAsFactors = FALSE) 

marks <- matrix(c(10,  9, 10,  6,  7,  8,
                  10,  9, 10,  8,  7,  8,
                  8, 10,  9,  7,  7,  7,
                  6,  8,  6,  8,  8,  9,
                  6,  8,  6, 10,  9, 10,
                  7,  6,  8, 10, 10,  8), nrow = nrow(df), ncol = 6)

rownames(marks) <- df$Name
colnames(marks) <- c('Math', 'Physics', 'Arts', 'Chemistry','Biology', 'History')

I have done a pretty simple solution, checking one by one, which worked to get to the right answer, but absolutely would not work if I had a huge dataset. Would anyone please help me find which was the "correct" way to solve it?

My solution:

for (i in marks[1,])
  print (i < 8)        
for (i in marks[2,])
  print (i < 8)        
for (i in marks[3,])
  print (i < 8)         
for (i in marks[4,])
  print (i < 8)         
for (i in marks[5,])
  print (i < 8)        
for (i in marks[6,])
  print (i < 8)   

  

I think should have a way of using for or apply functions, but I cant get it to work. I would appreciate any input, thank you very much!

2 Answers

We can just use comparison operators on a matrix or data.frame to create a logical matrix

i1 <- marks < 8

-output

i1
#        Math Physics  Arts Chemistry Biology History
#Ana    FALSE   FALSE FALSE      TRUE    TRUE    TRUE
#John   FALSE   FALSE FALSE     FALSE   FALSE    TRUE
#Joanna FALSE   FALSE FALSE      TRUE    TRUE   FALSE
#Anna    TRUE   FALSE  TRUE     FALSE   FALSE   FALSE
#Martin  TRUE    TRUE  TRUE     FALSE   FALSE   FALSE
#Katrin FALSE   FALSE  TRUE     FALSE   FALSE   FALSE

From the above output, if we need the count per student, use rowSums

rowSums(i1)
#   Ana   John Joanna   Anna Martin Katrin 
#    3      1      2      2      3      1 

Here is an option creating a dataframe to present "who has scored less than 8 on which subject"

idx <- which(marks < 8, arr.ind = TRUE)
data.frame(
  name = rownames(idx),
  subject = colnames(marks)[idx[, "col"]],
  mark = marks[idx]
)

which gives

     name   subject mark
1    Anna      Math    6
2  Martin      Math    7
3  Martin   Physics    7
4    Anna      Arts    7
5  Martin      Arts    7
6  Katrin      Arts    7
7     Ana Chemistry    6
8  Joanna Chemistry    6
9     Ana   Biology    6
10 Joanna   Biology    6
11    Ana   History    7
12   John   History    6
Related