1

I am using the following data and have come across a roadblock. I used read.csv to import my raw data into r.

# from OHP$ohp17.value
list(NULL, NULL, "19.9 nmol/L", "0.7 nmol/L", NULL, NULL, "22.6 nmol/L", "3.7 nmol/L", "6.6", "3.7")

I am wanting to use an if statement to tell me whether values within the variable OHP$ohp17.value are "low" or "high". My attempt

OHP$ohp17.value <- as.numeric(unlist(OHP$ohp17.value))
if(OHP$ohp17.value <18) print("Low") else print("High")

issues

Error: 'list' object cannot be coerced to type 'double'

I know that this is because there are units in the variable, not just numbers. I have tried to convert my variable into numbers using as.numeric().

4
  • 1
    You left a comment in staging ground that you are reading data with read.csv, though that does not really explain how you ended with such structure, a list column with NULL values. Could you open that csv in a text editor and include few lines from the top to your question, as text? Commented Nov 12, 2024 at 12:31
  • @Friede, I think you answer was fine as it was, I was just surprised by the way sub() handles a list with NULLs. Commented Nov 12, 2024 at 12:51
  • 2
    @margusl See help("as.character"): "For lists [...] it deparses the elements individually" Commented Nov 12, 2024 at 12:54
  • @margusl, unsure. It is not the safest methode and cannot be generalised in contrast to parse_number() (as long as there is only one number pattern per string). Commented Nov 12, 2024 at 13:02

3 Answers 3

2

You need to extract the number from the values first:

library(stringr)
data <- list(NULL, NULL, "19.9 nmol/L", "0.7 nmol/L", NULL, NULL, "22.6 nmol/L", "3.7 nmol/L", "6.6", "3.7")

ifelse(as.numeric(str_extract(data, "[0-9]+.?[0-9]*")) < 18, "low", "high")

Note that this approach ignores the unit and thus assumes all values are within the same unit, i.e. nmol/L.

Sign up to request clarification or add additional context in comments.

3 Comments

I've applied the extraction code as you've written above but some values are giving NA as a result but others are working fine (ie. extracting just the numbers). For example: Original values 1.9 nmol/L and 250 produce 1.90 and 250.00 respectively whereas an original value of 8 gives NA. Any idea why this might be? It seems to be values of 2 digits and without a decimal point which give NA.
Modify the regular expression to [0-9]+.?[0-9]* accordingly. You may have integers without a decimal point or white spaces in between.
That's worked! Thanks a lot :)
1

I suspect your data reading routine can be improved. This looks like an import issue.

If the data is already loaded, we can do in base R

x = as.numeric(sub("\\s.*", "", l)) # readr::parse_number(unlist(l))
y = ifelse(x > 18, "high", "low")

giving

> x
 [1]   NA   NA 19.9  0.7   NA   NA 22.6  3.7  6.6  3.7
> y
 [1] NA     NA     "high" "low"  NA     NA     "high" "low"  "low"  "low" 

Note

l = list(NULL, NULL, "19.9 nmol/L", "0.7 nmol/L", NULL, NULL, "22.6 nmol/L", "3.7 nmol/L", "6.6", "3.7")

1 Comment

Uh.. did certainly not expect c("NULL", "NULL", "19.9", ...) from sub("\\s.*", "", l)
1

It's somewhat "difficult" to construct a data.frame with NULL, but here we go

Data
OHP <- structure(list(dat = 1:10, ohp17.value = list(NULL, NULL, 
  "19.9 nmol/L", "0.7 nmol/L", NULL, NULL, "22.6 nmol/L", "3.7 nmol/L", 
  "6.6", "3.7")), row.names = c(NA, -10L), class = "data.frame")

Using parse_number with sapply to get single elements from the list, then replacing NULL with NA. Otherwise NULL gets omitted in unlist operations and the resulting vector will be truncated.

library(readr)

cbind(OHP, flag = c("high", "low")[(parse_number(sapply(OHP$ohp17.value, \(x) 
  if(is.null(x)) NA else x)) < 18) + 1])

output

   dat ohp17.value flag
1    1        NULL <NA>
2    2        NULL <NA>
3    3 19.9 nmol/L high
4    4  0.7 nmol/L  low
5    5        NULL <NA>
6    6        NULL <NA>
7    7 22.6 nmol/L high
8    8  3.7 nmol/L  low
9    9         6.6  low
10  10         3.7  low

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.