Search code examples
rfor-loopcountdataset

R Counting and storing in new dataframe goes wrong and produces duplicates


I have the following problem with this code

It does not produce the right count dataset. It needs to count for each werknemerID whether how long he is working. And when there is a new CAO, then it starts again with counting and the werknemerID gets a _1 etc.

So I expect based on the dummy dataset that it is like this:

data.frame(
  persoonsid = c("abc", "abc", "abc"), 
  werknemerID = c("ewrewr", "ewrewr_1", "blabla"), 
  Count = c(4, 2, 3), 
  Eerste_Maand = c("January", "May", "January"), 
  Jaar = c(2021, 2021, 2021), 
  CAO = c(40, 35, 40)
)

But it get this:

data.frame(persoonid = c("abc","abc","abc","abc","abc","abc"), werknemerID = c("ewrewr",ewrewr_1, ewrewr_2, blabla,blabla_1,blabla_2), count = c(4,2,3,4,2,3), Eerste_maand = c(January,May,January,January,May,January), Jaar = c(2021,2021,2021,2021,2021,2021), CAO = c(40,35,40,40,35,40).

This is the code that I'm using:

# Voorbeeld dataset
dataset <- data.frame(
  persoonsid = c("abc","abc","abc","abc","abc","abc","abc","abc","abc"),
  werknemerID = c("ewrewr", "ewrewr", "ewrewr", "ewrewr", "ewrewr", "ewrewr", "blabla", "blabla", "blabla"),
  Maand = c("January", "February", "March", "April", "May", "June", "January", "February", "March"),
  Jaar = c(2021, 2021, 2021, 2021, 2021, 2021, 2021, 2021, 2021),
  Code = c(82, 82, 82, 82, 82, 82, 82, 82, 82),
  CAO = c(40, 40, 40, 40, 35, 35, 40, 40, 40)
)

# Maand namen in juiste volgorde
maand_volgorde <- c("January", "February", "March", "April", "May", "June", 
                    "July", "August", "September", "October", "November", "December")

# Zet de Maand kolom om naar factor met de juiste volgorde
dataset$Maand <- factor(dataset$Maand, levels = maand_volgorde)

# Lege data frame om resultaten op te slaan
resultaten <- data.frame(
  persoonsid = character(), 
  werknemerID = character(), 
  Count = integer(), 
  Eerste_Maand = character(), 
  Jaar = integer(), 
  CAO = integer(), 
  stringsAsFactors = FALSE
)

# Functie om resultaten bij te werken
update_resultaten <- function(persoonsid, werknemerID, count, eerste_maand, jaar, cao) {
  nieuwe_rij <- data.frame(
    persoonsid = persoonsid,
    werknemerID = werknemerID,
    Count = count,
    Eerste_Maand = eerste_maand,
    Jaar = jaar,
    CAO = cao,
    stringsAsFactors = FALSE
  )
  return(nieuwe_rij)
}

# Unieke jaren in dataset
jaren <- unique(dataset$Jaar)

for (jaar in jaren) {
  # Filter dataset voor het huidige jaar
  dataset_jaar <- subset(dataset, Jaar == jaar)
  
  # Unieke persoonsids in het huidige jaar
  unieke_persoonsids <- unique(dataset_jaar$persoonsid)
  
  for (persoonsid in unieke_persoonsids) {
    # Filter dataset voor de huidige persoonsid
    data_persoonsid <- subset(dataset_jaar, persoonsid == persoonsid)
    
    # Unieke werknemerIDs voor de huidige persoonsid
    unieke_werknemerIDs <- unique(data_persoonsid$werknemerID)
    
    for (werknemerID in unieke_werknemerIDs) {
      # Filter dataset voor de huidige werknemerID
      data_id <- subset(data_persoonsid, werknemerID == werknemerID)
      
      # Variabele om de huidige CAO bij te houden en een teller voor de ID's
      huidige_cao <- NULL
      count <- 0
      suffix <- 0  # Initialiseren van de suffix teller
      eerste_maand <- NULL  # Initialiseren van de eerste maand
      
      for (i in 1:nrow(data_id)) {
        # Check if the CAO is different from the previous one
        if (!is.null(huidige_cao) && data_id$CAO[i] != huidige_cao) {
          # Save the count to the resultaten data frame
          resultaten <- rbind(resultaten, update_resultaten(
            persoonsid,
            ifelse(suffix == 0, werknemerID, paste(werknemerID, suffix, sep = "_")), 
            count, 
            eerste_maand, 
            jaar, 
            huidige_cao
          ))
          # Reset de teller, eerste maand en verhoog de suffix
          count <- 0
          suffix <- suffix + 1
          eerste_maand <- NULL
        }
        
        # Update the huidige CAO
        huidige_cao <- data_id$CAO[i]
        
        # Update the first month if it's NULL
        if (is.null(eerste_maand)) {
          eerste_maand <- as.character(data_id$Maand[i])
        }
        
        # Increase the count
        count <- count + 1
      }
      
      # Save the last count to the resultaten data frame
      resultaten <- rbind(resultaten, update_resultaten(
        persoonsid,
        ifelse(suffix == 0, werknemerID, paste(werknemerID, suffix, sep = "_")), 
        count, 
        eerste_maand, 
        jaar, 
        huidige_cao
      ))
    }
  }
}

# Bekijk de resultaten
print(resultaten)

Solution

  • Here's a compact solution based on the tidyverse (though I'm not 100% sure how you want to sort rows in your final data frame, so you may need to adjust the call to arrange):

    library(tidyverse)
    
    dataset %>% 
      mutate(Row = row_number()) %>% 
      group_by(persoonsid, werknemerID, CAO) %>% 
      summarise(
        Count = n(),
        Jaar = min(Jaar),
        # Temporary column to get correct ordering
        Row = min(Row),
        .groups = "keep"
      ) %>% 
      arrange(Row) %>% 
      select(-Row) %>% 
      # Fiddle suffices for werknemerID
      mutate(
        werknemerID = ifelse(
          row_number() > 1 & n() > 1, 
          paste0(werknemerID, "_", row_number() - 1), 
          werknemerID)
      ) %>% 
      # To avoid unexpected downstream behaviour
      ungroup()
    # A tibble: 3 × 5
      persoonsid werknemerID   CAO Count  Jaar
      <chr>      <chr>       <dbl> <int> <dbl>
    1 abc        ewrewr         40     4  2021
    2 abc        ewrewr_1       35     2  2021
    3 abc        blabla         40     3  2021