1

Background: PDF Parse My program looks for data in scanned PDF documents. I've created a CSV with rows representing various parameters to be searched for in a PDF, and columns for the different flavors of document that might contain those parameters. There are different identifiers for each parameter depending on the type of document. The column headers use dot separation to uniquely identify the document by type, subtype... , like so: type.subtype.s_subtype.s_s_subtype.

    t.s.s2.s3 t.s.s2.s3 t.s.s2.s3 t.s.s2.s3 ...
p1    str1                 str2
p2               str3      str4
p3    str5                           str6
p4               str7
...

I'm reading in PDF files, and based on the filepaths they can be uniquely categorized into one of these types. I can apply various logical conditions to a substring of a given filepath, and based on that I'd like to output an NxM Boolean matrix, where N = NROW(filepath_vector), and M = ncol(params_csv). This matrix would show membership of a given file in a type with TRUE, and FALSE elsewhere.

        t.s.s2.s3 t.s.s2.s3 t.s.s2.s3 t.s.s2.s3 ...
fpath1    FALSE     FALSE     TRUE      FALSE
fpath2    FALSE     TRUE      FALSE     FALSE
fpath3    FALSE     TRUE      FALSE     FALSE         
fpath4    FALSE     FALSE     FALSE     TRUE
...

My solution: I'm trying to apply a function to a matrix that takes a vector as argument, and applies the first element of the vector to the first row, the second element to the second row, etc... however, the function has conditional behavior depending on the element of the vector being applied.

I know this is very similar to the question below (my reference point), but the conditionals in my function are tripping me up. I've provided a simplified reproducible example of the issue below.

R: Apply function to matrix with elements of vector as argument

set.seed(300)

x <- y <- 5
m <- matrix(rbinom(x*y,1,0.5),x,y)

v <- c("321", "", "A160470", "7IDJOPLI", "ACEGIKM")

f <- function(x) {
  sapply(v, g <- function(y) {
    if(nchar(y)==8) {x=x*2
    } else if (nchar(y)==7) {
      if(grepl("^[[:alpha:]]*$", substr(y, 1, 1))) {x=x*3}
      else {x}
    } else if (nchar(y)<3) {x=x*4
    } else {x=x-2}
  })
}

mapply(f, as.data.frame(t(m)))

Desired output:

 #       [,1] [,2] [,3] [,4] [,5]
 # [1,]   -1    0   -1   -1   -1
 # [2,]    4    4    0    4    0
 # [3,]    3    0    3    3    0
 # [4,]    2    0    2    2    0
 # [5,]    1    1    1    1    0

But I get this error:

 Error in if (y == 8) { : missing value where TRUE/FALSE needed

Can't seem to figure out the error or if I'm misguided elsewhere in my entire approach, any thoughts are appreciated.

Update (03April2018):

I had provided this as a toy example for the sake of reproducibility, but I think it would be more informative to use something similar to my actual code with @grand_chat's excellent solution. Hopefully this helps someone who's struggling with a similar issue.

chk <- c(NA, "abc.TRO", "def.TRO", "ghi.TRO", "kjl.TRO", "mno.TRO")
len <- c(8, NA, NA)
seed <- c(FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE)
A = matrix(seed, nrow=3, ncol=6, byrow=TRUE)

pairs <- mapply(list, as.data.frame(t(A)), len, SIMPLIFY=F)

f <- function(pair) {
  x = unlist(pair[[1]])
  y = pair[[2]]
  if(y==8 & !is.na(y)) {
    x[c(grep("TRO", chk))] <- (x[c(grep("TRO", chk))] & TRUE)
  } else {x <- (x & FALSE)}
  return(x)
}

t(mapply(f, pairs))

Output:

# $v1       
# [1,]    FALSE   TRUE    TRUE    FALSE   FALSE   FALSE
# $v2
# [2,]    FALSE   FALSE   FALSE   FALSE   FALSE   FALSE
# $v3
# [3,]    FALSE   FALSE   FALSE   FALSE   FALSE   FALSE
jovianlynxdroid
  • 335
  • 3
  • 5
  • 14

1 Answers1

1

You're processing the elements of vector v and the rows of your matrix m (columns of data frame t(m)) in parallel, so you could zip the corresponding elements into a list of pairs and process the pairs. Try this:

x <- y <- 5
m <- matrix(rbinom(x*y,1,0.5),x,y)

v <- c("321", "", "A160470", "7IDJOPLI", "ACEGIKM")

# Zip into pairs:
pairs <- mapply(list, as.data.frame(t(m)), v, SIMPLIFY=F)

# Define a function that acts on pairs:
f <- function(pair) {
    x = pair[[1]]
    y = pair[[2]]
    if(nchar(y)==8) {x=x*2
    } else if (nchar(y)==7) {
      if(grepl("^[[:alpha:]]*$", substr(y, 1, 1))) {x=x*3}
      else {x}
    } else if (nchar(y)<3) {x=x*4
    } else {x=x-2}
  }

# Apply it:
mapply(f, pairs, SIMPLIFY=F)

with result:

$V1
[1] -2 -1 -2 -2 -1

$V2
[1] 4 4 0 0 4

$V3
[1] 3 3 3 3 0

$V4
[1] 2 0 2 2 0

$V5
[1] 0 0 3 0 3

(This doesn't agree with your desired output because you don't seem to have applied your function f properly.)

grand_chat
  • 431
  • 3
  • 3
  • Thanks for this solution! I tried to apply it to my actual code, and I ended up with weird output that I wasn't able to troubleshoot, so I've updated my question with that - would appreciate your input if you have any ideas. I'm not sure if accepting your solution closes off the question so people won't be able to see it, so I'll hold off for now - but I think it's the best approach. – jovianlynxdroid Apr 03 '18 at 21:56
  • Never mind - figured it out! Updated my question to apply your solution with my actual code, for illustrative purposes. – jovianlynxdroid Apr 03 '18 at 22:57