R Function to Create Custom Data Frames from Larger Data Frame

Viewed 67

Ok, So I found somewhat similar questions asked of this already, but I'm not quite getting it. So, here is my example. I have a very large table of data that has a basic setup like the small example data below. I will try to explain very clearly what I am wanting to do. I'm guessing maybe it's easier to do than I think, but I'm not really good at creating functions or for-loops at this point, and I'm guessing that's what I need. So here is the basic setup for my data.

test_year <- c(2019,2019,2019,2020,2020,2020,2021,2021,2021)
SN <- c(1001,1002,1003,1004,1005,1006,1007,1008,1009)
Owner <- c("Adam","Bob","Bob","Carl","Adam","Bob","Adam","Carl","Adam")
ObsA <- c(0,0,1,1,0,1,1,NA,1)
ObsB <- c(1,1,1,0,0,0,0,0,1)
ObsC <- c(0,0,0,0,1,1,0,0,0)

df <- data.frame(test_year, SN, Owner, ObsA, ObsB, ObsC)

From this, I need to be able to create smaller data frames by selecting individual observation columns. So if this were a small data set:

df_A <- df %>% select(test_year, SN, Owner, ObsA)

and then have a data frame for each of the other observations. And yes, it is easier to select the columns that I want versus the columns I don't want as most of the columns selected will be standard, and I just need to change which observation is picked out of over 40 in my real data.

From these smaller data frames, I will be doing numerous other operations including making multiple tables and graphs. As examples, the following are similar to the types of graphs I will make (with some additional formatting that is simple enough). Notice too in these graphs a title that is based on (though not identical to), the column selected.

df_A[is.na(df_A)] = 0
df_A
df_A %>% group_by(test_year) %>% 
   summarize(n = n(), obs = sum(ObsA)) %>%
   ggplot(aes(x = test_year, y = 100*obs/n)) +
   ggtitle("Observation A") +
   geom_point()
  
df_A %>% group_by(Owner) %>%
   summarize(n = n(), obs = sum(ObsA)) %>%
   ggplot(aes(x = Owner, y = 100*obs/n)) +
   ggtitle("Observation A") +
   geom_bar(stat = "identity") +
   coord_flip() +
   scale_x_discrete()

As I said, additional analysis will also need to be done. So, I'm needing help figuring out how I can structure a function to do what it is I'm wanting to do. Thanks!

1 Answers

Here is a way to return a list of plots.

Split all the 'Obs' columns in a list of dataframes, use imap to pass dataframe along with the column name (to use it as title).

library(tidyverse)

common_cols <- 1:3
df[is.na(df)] = 0

list_plots <- df %>%
  select(starts_with('Obs')) %>%
  split.default(names(.)) %>%
  imap(~{
    tmp <- df[common_cols] %>% bind_cols(.x)
    tmp %>% group_by(test_year) %>% 
      summarize(n = n(), obs = sum(.data[[.y]])) %>%
      ggplot(aes(x = factor(test_year), y = 100*obs/n)) +
      geom_point() +
      labs(x = 'Year', y = 'ratio', title = .y)
    })

Individual plots can be accessed by list_plots[[1]],list_plots[[2]] etc.

Related