3
votes

I have a list within data frame on which I want to use purrr::map() to test whether there are any NULL elements and then get rid of them.

While I was able to do this using sapply, but map doesn't work. I read https://cran.r-project.org/web/packages/purrr/purrr.pdf, but I can't figure out what's I am missing.

Here's my sapply code --this works well:

P_Trans<- P_Trans[!sapply(P_Trans$Group,is.null),] 

Here's are a few things I tried for purrr::map, but they don't work.

Here are the four things I tried:

a)

P_Trans %>% purrr::map(.,~is.null(Group))

b)

P_Trans %>% purrr::map(.,~is.null(.$Group))

c)

P_Trans %>% purrr::map(~is.null(.$Group))

d)

P_Trans %>% purrr::map(~is.null(Group))

Can someone please correct my mistake, and let me know what I is that I am doing wrong with above four options?


Data:

dput(P_Trans)

structure(list(TransactionID = c("a1", "a1", "a1", "a2", "a2", 
"a2", "a3", "a3", "a3", "a3", "a4", "a5", "a5", "a5", "a5", "a5", 
"a6", "a6", "a7"), ProductID = c("A", "B", "1", "C", "4", "5", 
"D", "C", "7", "8", "H", "1", "2", "3", "3", "1", "H", "15", 
"22"), ProductType = c(1, 1, 2, 1, 2, 2, 1, 1, 2, 2, 1, 2, 2, 
2, 2, 2, 1, 2, 3), Group = list(structure(list(Group = "Group1"), .Names = "Group", row.names = c(NA, 
-1L), class = c("tbl_df", "tbl", "data.frame")), structure(list(
    Group = "Group1"), .Names = "Group", row.names = c(NA, -1L
), class = c("tbl_df", "tbl", "data.frame")), structure(list(
    Group = "Group1"), .Names = "Group", row.names = c(NA, -1L
), class = c("tbl_df", "tbl", "data.frame")), structure(list(
    Group = c("Group2", "Group3")), .Names = "Group", row.names = c(NA, 
-2L), class = c("tbl_df", "tbl", "data.frame")), structure(list(
    Group = "Group2"), .Names = "Group", row.names = c(NA, -1L
), class = c("tbl_df", "tbl", "data.frame")), structure(list(
    Group = "Group2"), .Names = "Group", row.names = c(NA, -1L
), class = c("tbl_df", "tbl", "data.frame")), structure(list(
    Group = "Group3"), .Names = "Group", row.names = c(NA, -1L
), class = c("tbl_df", "tbl", "data.frame")), structure(list(
    Group = c("Group2", "Group3")), .Names = "Group", row.names = c(NA, 
-2L), class = c("tbl_df", "tbl", "data.frame")), structure(list(
    Group = "Group3"), .Names = "Group", row.names = c(NA, -1L
), class = c("tbl_df", "tbl", "data.frame")), structure(list(
    Group = "Group3"), .Names = "Group", row.names = c(NA, -1L
), class = c("tbl_df", "tbl", "data.frame")), structure(list(
    Group = "Group5"), .Names = "Group", row.names = c(NA, -1L
), class = c("tbl_df", "tbl", "data.frame")), structure(list(
    Group = "Group1"), .Names = "Group", row.names = c(NA, -1L
), class = c("tbl_df", "tbl", "data.frame")), structure(list(
    Group = "Group1"), .Names = "Group", row.names = c(NA, -1L
), class = c("tbl_df", "tbl", "data.frame")), structure(list(
    Group = "Group1"), .Names = "Group", row.names = c(NA, -1L
), class = c("tbl_df", "tbl", "data.frame")), structure(list(
    Group = "Group1"), .Names = "Group", row.names = c(NA, -1L
), class = c("tbl_df", "tbl", "data.frame")), structure(list(
    Group = "Group1"), .Names = "Group", row.names = c(NA, -1L
), class = c("tbl_df", "tbl", "data.frame")), structure(list(
    Group = "Group5"), .Names = "Group", row.names = c(NA, -1L
), class = c("tbl_df", "tbl", "data.frame")), structure(list(
    Group = "Group5"), .Names = "Group", row.names = c(NA, -1L
), class = c("tbl_df", "tbl", "data.frame")), NULL)), class = c("tbl_df", 
"tbl", "data.frame"), row.names = c(NA, -19L), .Names = c("TransactionID", 
"ProductID", "ProductType", "Group"))
1
P_Trans[!map_lgl(P_Trans$Group,is.null),]? - Nate
@NathanDay - Wow! Thank you. This works well. However, could you please comment on my mistakes? I am fairy new to dplyr so this will help me to learn the concepts. I'd appreciate your thoughts. - watchtower
I really only use map when I have a list of data.frames I want to iterate over, usually for modeling. By default map is trying to return a list and using a wrapper like map-lgl is just forcing the result into vector form similar to what map(p_trans$Group, is.null) %>% unlist would do, but still preserving names and what not :) Hope that helps, map still gives me fits sometimes and I go back to the xapply - Nate
Why not just use purrr::discard()? - hrbrmstr

1 Answers

0
votes

With all your solutions:

  • you're looping through every column of P_Trans (not through items/rows)
  • these columns are atomic vectors, the list (or data.frame) has names, the atomic vectors don't have a name. names(P_Trans[[1]]) # NULL
  • you're intending to return a list, not a data.frame, though it crashes before
  • a is identical to c
  • b is identical to d

a) P_Trans %>% purrr::map(.,~is.null(Group)) :

  • Group doesn't exist, nothing here tells us we should look for it in the current item, even less in the table

b) P_Trans %>% purrr::map(.,~is.null(.$Group))

  • you're looping through 4 atomic vectors, each time looking for an element named Group, none has any (even the 4th one), so $ operator is invalid for atomic vectors

lmap would have helped you loop through columns as length one sublists of P_Trans but approach would have crashed too, only last item would have had an item named Group (names(P_Trans[4]) # "Group").

The map equivalent of your solution is P_Trans[!map_lgl(P_Trans$Group,is.null),] as @Nate commented because map_lgl is designed to return a vector of logical like your sapply did:

Other ways to get what you want:

P_Trans %>% rowwise %>% filter(!is.null(Group))
P_Trans %>% filter(lengths(Group)!=0)
P_Trans[lengths(P_Trans$Group)!=0,]