rfunctioncumulative-frequency

R help needed for my cumulative percentage function


A recent change (be it in R or somewhere else) has made my previously working function stop working. The function is designed to generate two columns that tell me what the percentile score (see df2$CumPercent is for a given score on a survey (see df2$V1). I have therefore made a few changes to the manual version of the logic, which is working well. When I apply the same logic within a function it spits out an error stating that the Var1 variable is not found. Any ideas what might be going wrong here?

df5 <- structure(list(MyVariable = c(4.66666666666667, 2.16666666666667, 
                                     5.66666666666667, 4.5, 5.16666666666667, 4.5, 1, 3.83333333333333, 
                                     2, 4, 2.33333333333333, 5.5, 5.66666666666667, 2.66666666666667, 
                                     5.66666666666667, 2.83333333333333, 4.33333333333333, 5.33333333333333, 
                                     5.66666666666667, 4.33333333333333, 2.33333333333333, 4.5, 3.66666666666667, 
                                     3.83333333333333, 2, 5, 2.83333333333333, 3, 4.83333333333333, 
                                     5.16666666666667, 3, 5.16666666666667, 1.33333333333333, 5.16666666666667, 
                                     2.16666666666667, 4, 3.66666666666667, 4, 3.5, 4.5, 3, 5.16666666666667, 
                                     4.83333333333333, 4.66666666666667, 3.16666666666667, 4.16666666666667, 
                                     2.83333333333333, 4.83333333333333, 2.66666666666667, 4.16666666666667, 
                                     5.16666666666667, 6.16666666666667, 1.83333333333333, 3.33333333333333, 
                                     4.5, 4.83333333333333, 5.5, 4.33333333333333, 4.33333333333333, 
                                     4.83333333333333, 2.33333333333333, 4.5, 4.16666666666667, 5.5, 
                                     4.5, 4.83333333333333, 5, 1, 4.5, 5, 2.33333333333333, 4, 3.5, 
                                     3.33333333333333, 4.66666666666667, 1.5, 5.83333333333333, 4.33333333333333, 
                                     5.16666666666667, 3.33333333333333, 4.66666666666667, 6, 4.33333333333333, 
                                     2.16666666666667, 4.16666666666667, 5.83333333333333, 3.66666666666667, 
                                     5, 5.83333333333333, 4.33333333333333, 4.33333333333333, 4.66666666666667, 
                                     4.83333333333333, 5.16666666666667, 5, 3.5, 5, 5.5, 4.66666666666667, 
                                     5.33333333333333, 5.5, 3.66666666666667, 1.83333333333333, 2.33333333333333, 
                                     5, 5.83333333333333, 4.66666666666667, 4.83333333333333, 5.83333333333333, 
                                     3.66666666666667, 3.33333333333333, 2.5, 5.33333333333333, 4.16666666666667, 
                                     4.16666666666667, 3.5, 3, 5.16666666666667, 3.66666666666667, 
                                     5.83333333333333, 4, 5.33333333333333, 6, 3.16666666666667, 2.33333333333333, 
                                     4.66666666666667, 5.66666666666667, 3.5, 4.66666666666667, 1.33333333333333, 
                                     4, 4.33333333333333, 3.5, 3.16666666666667, 5.16666666666667, 
                                     4.66666666666667, 2.83333333333333, 4, 2.5, 2.83333333333333, 
                                     4.83333333333333, 5.33333333333333, 4.5, 3.83333333333333, 4)), row.names = c(NA, 
                                                                                                                   -145L), class = "data.frame")

#Manual version of the cumulative percent logic (which works as intended)
PercentilesRaw <- data.frame(seq(from=0, to=7, by=.01)) #Create every increment of percentile as vector
colnames(PercentilesRaw)[colnames(PercentilesRaw)=="seq.from...0..to...7..by...0.01."] <- "V1" #Rename percentile column name
df <- data.frame(table(df5$MyVariable)) #Count the number of original values in the column
df[,"Var1"] <- as.numeric(as.character(df[,"Var1"])) #The table function above produces factor levels so need to convert to numeric
V1 <- df[,"Var1"] #Make a vector from the Var1 column
Frequency <- df[,"Freq"] #Make a vector from the Freq column
CumSum <- cumsum(df[,"Freq"]) #Calculate a cumulative sum from the Freq column
CumPercent <- CumSum/sum(df[,"Freq"])*100 #Calculate the cumulative percentage vector
CumPercent <- round(CumPercent,2) #Round the cumulative percentage vector to 2 dp
output <- cbind(round(V1,2), CumPercent) #Map the cumulative percent results to the V1 vector
df2 <- data.frame(output) #Convert the two columns into a df

#Now attempt to convert into a function.
cpave1 <- function(x) {
  PercentilesRaw <- data.frame(seq(from=0, to=7, by=.01)) #Create every increment of percentile as vector
  colnames(PercentilesRaw)[colnames(PercentilesRaw)=="seq.from...0..to...7..by...0.01."] <- "V1" #Rename percentile column name
  df <- data.frame(table(x)) #Count the number of original values in the column
  df[,"Var1"] <- as.numeric(as.character(df[,"Var1"])) #The table function above produces factor levels so need to convert to numeric
  V1 <- df[,"Var1"] #Make a vector from the Var1 column
  Frequency <- df[,"Freq"] #Make a vector from the Freq column
  CumSum <- cumsum(df[,"Freq"]) #Calculate a cumulative sum from the Freq column
  CumPercent <- CumSum/sum(df[,"Freq"])*100 #Calculate the cumulative percentage vector
  CumPercent <- round(CumPercent,2) #Round the cumulative percentage vector to 2 dp
  output <- cbind(round(V1,2), CumPercent) #Map the cumulative percent results to the V1 vector
  df2 <- data.frame(output) #Convert the two columns into a df
}

#Apply function to the MyVariable column.
MyVariable <- cpave1(df5$MyVariable)

Solution

  • As the error message suggests there is no "Var1" column in your data. The column is called x. Here is a shorter and updated version of your function which returns the same output.

    cpave1 <- function(x) {
      df <- type.convert(data.frame(table(x)), as.is = TRUE)
      data.frame(V1 = round(df$x ,2), 
                 CumPercent = round(cumsum(df$Freq)/sum(df$Freq)*100, 2))
    }
    cpave1(df5$MyVariable)
    
    #     V1 CumPercent
    #1  1.00       1.38
    #2  1.33       2.76
    #3  1.50       3.45
    #4  1.83       4.83
    #5  2.00       6.21
    #6  2.17       8.28
    #7  2.33      12.41
    #8  2.50      13.79
    #...