1

I've seen many posts concerning the warning Unknown levels in `f`: , however, all of them concerned the fact that the variable wasn't a factor before using fct_collapse(). All my variables are already factors, but I'm getting this warning nevertheless. How can I get rid of Unknown levels in `f`: ?

Data contains number of hours (in Portuguese, I'm sorry) as very big strings. I want to make the strings shorter. Hence, for example 'Mais de 10 horas em língua adicional' (more than 10 hours in additional language) should become '> 10'. That's the idea.

  • my code:
data %>% 
       mutate(across(-SCHOOL, ~ fct_collapse(.,
                                     'Não oferta' = c('Não oferecemos este nível de ensino na escola', 
                                                      'Não oferecemos este nível de ensino bilíngue na escola'), 
                                     '> 20h' = c('Mais de 20 horas/ períodos semanais'),
                                     '> 10h' = c('Mais de 10 horas/ períodos semanais', 
                                                 'Mais de 10 horas em língua adicional'),
                                     '= 20h' = c('20 horas/ períodos semanais'),
                                     'Até 10h' = c('Até 10 horas/períodos semanais'),
                                     '= 1h' = c('1 hora em língua adicional'),
                                     '100% CH' = c('100% da carga-horária em língua adicional'),
                                     '> 15h' = c('Mais de 15 horas/ períodos semanais'),
                                     '> 30h' = c('Mais de 30 horas/ períodos semanais'),
                                     '50% CH' = c('50% da carga- horária em língua adicional',
                                     '= 3h' = c('3 horas em língua adicional'),
                                     '= 6h' = c('6 horas em língua adicional'),
                                     '= 5h' = c('5 horas em língua adicional'),
                                     '= 2h' = c('2 horas em língua adicional'),
                                     '= 10h' = c('10 horas em língua adicional'),
                                     '9h' = c('9 horas em língua adicional'),
                                     '8h' = c('8 horas em língua adicional', 
                                              '8 horas em aíngua adicional'), ## digitação
                                     '3h' = c('3 horas em língua adicional'),
                                     '4h' = c('4 horas em língua adicional'),
                                     '7h' = c('7 horas em língua adicional'),
                                     '2h' = c('2 horas em língua adicional')))))
  • How can I come over this? I'm getting 14 Unknown levels in `f`:. Thanks in adv!

  • my data:

# Note: I've excluded the ```school``` column to preserve participants' id

dput(my_data)
structure(list(Q21 = structure(c(5L, 5L, 5L, 4L, 3L, 5L, 4L, 
5L, 5L, 5L, 5L, 1L, 2L, 5L, 5L, 5L, 5L, 1L, 5L, 5L, 5L, 5L, 5L, 
5L, 4L, 5L, 5L, 2L, 5L), .Label = c("20 horas/ períodos semanais", 
"Até 10 horas/períodos semanais", "Mais de 10 horas/ períodos semanais", 
"Mais de 20 horas/ períodos semanais", "Não oferecemos este nível de ensino na escola"
), class = "factor"), Q22 = structure(c(1L, 2L, 1L, 4L, 3L, 4L, 
5L, 1L, 6L, 6L, 6L, 1L, 2L, 6L, 6L, 6L, 2L, 1L, 6L, 6L, 6L, 6L, 
3L, 6L, 5L, 2L, 6L, 2L, 5L), .Label = c("20 horas/ períodos semanais", 
"Até 10 horas/períodos semanais", "Mais de 10 horas/ períodos semanais", 
"Mais de 15 horas/ períodos semanais", "Mais de 20 horas/ períodos semanais", 
"Não oferecemos este nível de ensino na escola"), class = "factor"), 
    Q23 = structure(c(4L, 2L, 4L, 4L, 3L, 4L, 5L, 1L, 5L, 5L, 
    1L, 1L, 2L, 6L, 4L, 3L, 2L, 1L, 3L, 6L, 6L, 4L, 3L, 4L, 4L, 
    1L, 1L, 2L, 1L), .Label = c("20 horas/ períodos semanais", 
    "Até 10 horas/períodos semanais", "Mais de 10 horas/ períodos semanais", 
    "Mais de 15 horas/ períodos semanais", "Mais de 20 horas/ períodos semanais", 
    "Não oferecemos este nível de ensino na escola"), class = "factor"), 
    Q24 = structure(c(5L, 3L, 1L, 4L, 3L, 4L, 5L, 4L, 1L, 1L, 
    1L, 1L, 2L, 7L, 4L, 3L, 1L, 1L, 3L, 5L, 2L, 5L, 3L, 5L, 4L, 
    6L, 1L, 4L, 1L), .Label = c("20 horas/ períodos semanais", 
    "Até 10 horas/períodos semanais", "Mais de 10 horas/ períodos semanais", 
    "Mais de 15 horas/ períodos semanais", "Mais de 20 horas/ períodos semanais", 
    "Mais de 30 horas/ períodos semanais", "Não oferecemos este nível de ensino na escola"
    ), class = "factor"), Q25 = structure(c(5L, 3L, 5L, 4L, 4L, 
    4L, 5L, 2L, 1L, 1L, 1L, 1L, 2L, 7L, 4L, 3L, 1L, 1L, 3L, 5L, 
    2L, 5L, 3L, 5L, 4L, 6L, 5L, 4L, 1L), .Label = c("20 horas/ períodos semanais", 
    "Até 10 horas/períodos semanais", "Mais de 10 horas/ períodos semanais", 
    "Mais de 15 horas/ períodos semanais", "Mais de 20 horas/ períodos semanais", 
    "Mais de 30 horas/ períodos semanais", "Não oferecemos este nível de ensino na escola"
    ), class = "factor"), Q26 = structure(c(5L, 7L, 5L, 4L, 4L, 
    4L, 5L, 2L, 5L, 5L, 1L, 1L, 2L, 4L, 5L, 4L, 7L, 7L, 3L, 6L, 
    2L, 5L, 3L, 5L, 1L, 6L, 5L, 4L, 5L), .Label = c("20 horas/ períodos semanais", 
    "Até 10 horas/períodos semanais", "Mais de 10 horas/ períodos semanais", 
    "Mais de 15 horas/ períodos semanais", "Mais de 20 horas/ períodos semanais", 
    "Mais de 30 horas/ períodos semanais", "Não oferecemos este nível de ensino na escola"
    ), class = "factor"), Q27 = structure(c(6L, 7L, 6L, 1L, 4L, 
    4L, 5L, 2L, 6L, 6L, 7L, 5L, 3L, 4L, 5L, 7L, 7L, 7L, 3L, 6L, 
    7L, 7L, 4L, 6L, 7L, 6L, 7L, 5L, 6L), .Label = c("20 horas/ períodos semanais", 
    "Até 10 horas/períodos semanais", "Mais de 10 horas/ períodos semanais", 
    "Mais de 15 horas/ períodos semanais", "Mais de 20 horas/ períodos semanais", 
    "Mais de 30 horas/ períodos semanais", "Não oferecemos este nível de ensino na escola"
    ), class = "factor"), Q28 = structure(c(1L, 1L, 1L, 1L, 7L, 
    5L, 1L, 1L, 1L, 1L, 1L, 1L, 3L, 9L, 1L, 6L, 1L, 4L, 1L, 1L, 
    1L, 1L, 1L, 2L, 1L, 1L, 1L, 8L, 1L), .Label = c("", "1º a 4º ano do Fundamental 1: 27h/aula total, 21h/aula em Língua Portuguesa\n5º ano Fundamental 1: 30h/a total, 24h/a em Língua Portuguesa\n6º ao 8º Fundamental II: 29h/a total, 27h/a em Língua Portuguesa\n9º, Fundamental II: 36h/a total, 34h/a em Língua Portuguesa\n1ª série, EM: ainda em discussão\n2ª série, EM: ainda em discussão\n3ª série, EM: ainda em discussão", 
    "Até 4 anos: 1 aula de cultura brasileira\n5 anos: 5 aulas por semana\n6-10 anos: 7 aulas - sendo 5 portugues, 2 estudos sociais\nAcima: 9 aulas", 
    "Em inglês, L2, oferecemos no EI 22h30 e no EFI 10h semanalmente", 
    "Inglês: Nível 1 e 2 (1 ano a 2 anos) 30min semanais; nível 3, 4 e 5 (3 a 5 anos) 1h20semanal; ensino fundamental 1h30 (semanal) obs. Carga horaria tradicional: 2 encontros de 50min", 
    "Na educação infantil, cerca de 15% do currículo é ministrado em língua portuguesa. No Ensino Fundamental 1, 50% são ministradas em língua portuguesa. No Ensino Fundamental 2, 60% são ministradas em língua portuguesa.", 
    "No ensino médio a prática de Laboratório  de redação é mais latente.", 
    "O aumento da carga horária é gradativa, conforme a idade e os segmentos.", 
    "Temos duas trilhas no Ensino Médio: trilha nacional e a trilha internacional. Na Nacional, os tempos em inglês são reduzidos, do total de 32 aulas de aula (sem contar intervalos e almoço) somente 4 aulas de 1 hora são em inglês. Na trilha internacional, das 32 aulas 14 delas são em língua inglesa. "
    ), class = "factor"), Q29 = structure(c(5L, 5L, 5L, 5L, 5L, 
    1L, 5L, 5L, 5L, 5L, 5L, 5L, 2L, 5L, 5L, 5L, 5L, 3L, 5L, 5L, 
    5L, 5L, 5L, 5L, 5L, 5L, 5L, 4L, 5L), .Label = c("1 hora em língua adicional", 
    "100% da carga-horária em língua adicional", "50% da carga- horária em língua adicional", 
    "Mais de 10 horas em língua adicional", "Não oferecemos este nível de ensino bilíngue na escola"
    ), class = "factor"), Q30 = structure(c(7L, 3L, 5L, 9L, 1L, 
    1L, 9L, 4L, 9L, 9L, 9L, 4L, 2L, 9L, 9L, 9L, 6L, 6L, 9L, 9L, 
    9L, 9L, 2L, 9L, 9L, 4L, 9L, 8L, 1L), .Label = c("1 hora em língua adicional", 
    "10 horas em língua adicional", "100% da carga-horária em língua adicional", 
    "3 horas em língua adicional", "5 horas em língua adicional", 
    "50% da carga- horária em língua adicional", "6 horas em língua adicional", 
    "Mais de 10 horas em língua adicional", "Não oferecemos este nível de ensino bilíngue na escola"
    ), class = "factor"), Q31 = structure(c(10L, 3L, 11L, 10L, 
    12L, 1L, 5L, 5L, 6L, 5L, 7L, 5L, 3L, 13L, 7L, 12L, 8L, 8L, 
    2L, 13L, 2L, 9L, 2L, 9L, 10L, 7L, 4L, 12L, 7L), .Label = c("1 hora em língua adicional", 
    "10 horas em língua adicional", "100% da carga-horária em língua adicional", 
    "2 horas em língua adicional", "3 horas em língua adicional", 
    "4 horas em língua adicional", "5 horas em língua adicional", 
    "50% da carga- horária em língua adicional", "6 horas em língua adicional", 
    "8 horas em aíngua adicional", "9 horas em língua adicional", 
    "Mais de 10 horas em língua adicional", "Não oferecemos este nível de ensino bilíngue na escola"
    ), class = "factor"), Q32 = structure(c(12L, 8L, 2L, 11L, 
    12L, 1L, 6L, 5L, 7L, 7L, 9L, 5L, 3L, 13L, 10L, 8L, 4L, 2L, 
    2L, 11L, 2L, 10L, 2L, 9L, 12L, 7L, 5L, 12L, 7L), .Label = c("1 hora em língua adicional", 
    "10 horas em língua adicional", "100% da carga-horária em língua adicional", 
    "2 horas em língua adicional", "3 horas em língua adicional", 
    "4 horas em língua adicional", "5 horas em língua adicional", 
    "50% da carga- horária em língua adicional", "6 horas em língua adicional", 
    "7 horas em língua adicional", "8 horas em aíngua adicional", 
    "Mais de 10 horas em língua adicional", "Não oferecemos este nível de ensino bilíngue na escola"
    ), class = "factor"), Q33 = structure(c(7L, 8L, 2L, 11L, 
    12L, 1L, 6L, 5L, 7L, 7L, 10L, 5L, 3L, 13L, 10L, 8L, 4L, 2L, 
    2L, 11L, 2L, 10L, 2L, 9L, 12L, 7L, 5L, 12L, 7L), .Label = c("1 hora em língua adicional", 
    "10 horas em língua adicional", "100% da carga-horária em língua adicional", 
    "2 horas em língua adicional", "3 horas em língua adicional", 
    "4 horas em língua adicional", "5 horas em língua adicional", 
    "50% da carga- horária em língua adicional", "6 horas em língua adicional", 
    "7 horas em língua adicional", "8 horas em aíngua adicional", 
    "Mais de 10 horas em língua adicional", "Não oferecemos este nível de ensino bilíngue na escola"
    ), class = "factor"), Q34 = structure(c(7L, 11L, 2L, 5L, 
    2L, 1L, 6L, 4L, 5L, 7L, 8L, 11L, 3L, 10L, 8L, 10L, 11L, 11L, 
    11L, 9L, 8L, 9L, 11L, 11L, 2L, 7L, 5L, 10L, 7L), .Label = c("1 hora em língua adicional", 
    "10 horas em língua adicional", "100% da carga-horária em língua adicional", 
    "2 horas em língua adicional", "3 horas em língua adicional", 
    "4 horas em língua adicional", "5 horas em língua adicional", 
    "7 horas em língua adicional", "8 horas em aíngua adicional", 
    "Mais de 10 horas em língua adicional", "Não oferecemos este nível de ensino bilíngue na escola"
    ), class = "factor"), Q35 = structure(c(5L, 9L, 9L, 4L, 9L, 
    9L, 4L, 3L, 3L, 3L, 9L, 9L, 6L, 8L, 7L, 9L, 9L, 9L, 9L, 9L, 
    9L, 9L, 9L, 9L, 9L, 9L, 9L, 2L, 1L), .Label = c("1 hora em língua adicional", 
    "10 horas em língua adicional", "2 horas em língua adicional", 
    "3 horas em língua adicional", "5 horas em língua adicional", 
    "50% da carga- horária em língua adicional", "6 horas em língua adicional", 
    "Mais de 10 horas em língua adicional", "Não oferecemos este nível de ensino bilíngue na escola"
    ), class = "factor")), row.names = c(NA, -29L), class = "data.frame")
Larissa Cury
  • 806
  • 2
  • 11

1 Answers1

1

Simple solution is to make sure that all factors have all the possible levels you may need - the warning messages are just letting you know that they're not all noted in all columns.

You can simply assign all columns the correct set of levels first, which will eliminate the warning messages. This will not change the values in any of the coluns, but will tell R that in principle it should expect all of these to be a valid value in all columns.

The line:

all_levels <- lapply(my_data, levels) |> reduce(c) |> unique()

Will concatenate all the levels you have already across all columns into a vector. fct_expand will then expand the list of possible values for each column, so that when fct_collapse checks each one it finds what it expects there.

library(tidyverse)

all_levels <- lapply(my_data, levels) |> reduce(c) |> unique()

my_data %>% 
  mutate(
    across(everything(), fct_expand, all_levels),
         across(everything(), fct_collapse,
                                        'Não oferta' = c('Não oferecemos este nível de ensino na escola', 
                                                         'Não oferecemos este nível de ensino bilíngue na escola'), 
                                        '> 20h' = c('Mais de 20 horas/ períodos semanais'),
                                        '> 10h' = c('Mais de 10 horas/ períodos semanais', 
                                                    'Mais de 10 horas em língua adicional'),
                                        '= 20h' = c('20 horas/ períodos semanais'),
                                        'Até 10h' = c('Até 10 horas/períodos semanais'),
                                        '= 1h' = c('1 hora em língua adicional'),
                                        '100% CH' = c('100% da carga-horária em língua adicional'),
                                        '> 15h' = c('Mais de 15 horas/ períodos semanais'),
                                        '> 30h' = c('Mais de 30 horas/ períodos semanais'),
                                        '50% CH' = c('50% da carga- horária em língua adicional',
                                                     '= 3h' = c('3 horas em língua adicional'),
                                                     '= 6h' = c('6 horas em língua adicional'),
                                                     '= 5h' = c('5 horas em língua adicional'),
                                                     '= 2h' = c('2 horas em língua adicional'),
                                                     '= 10h' = c('10 horas em língua adicional'),
                                                     '9h' = c('9 horas em língua adicional'),
                                                     '8h' = c('8 horas em língua adicional', 
                                                              '8 horas em língua adicional'), ## digitação
                                                     '3h' = c('3 horas em língua adicional'),
                                                     '4h' = c('4 horas em língua adicional'),
                                                     '7h' = c('7 horas em língua adicional'),
                                                     '2h' = c('2 horas em língua adicional'))))

fct_expand increases the levels of a factor - i.e. the list of valid values it can take - without modifying the data itself. The levels are distinct from the values, e.g.:

l <- factor(letters[1:3])

l
#> [1] a b c
#> Levels: a b c

l <- forcats::fct_expand(l, letters[1:5])

l
#> [1] a b c
#> Levels: a b c d e
Andy Baxter
  • 5,833
  • 1
  • 8
  • 22
  • Hi, @Andy Baxter, thank you very much! Would you expand on *the warning messages are just letting you know that they're not all noted in all columns* ? I don't think I got the reason behind the warning yet. Oh, there was a typo in '8h' ! it should have been 'língua' ('language', in Portuguese) not 'aíngua' and I haven't noticed before that I haven't closed its last ```)``` as well – Larissa Cury Feb 10 '23 at 12:07
  • 1
    Ah that explains the level it didn't find :). To explain the warning messages - if you run `str(my_data)` it will show you that across the Q columns not all of them have 30 levels (which is the total number of possible values). Some only have 7, 8 or 9 levels. This might be because when reading in your data R has read each column separately, seen only 7 unique values in that column and made it a factor of 7 levels. When you ask `mutate` to collapse a list of levels that you've given it it checks whether each level is possible in that column and warns you if it's not. Above method fixes this. – Andy Baxter Feb 10 '23 at 12:28
  • thank you very much, I think I got it now! So we're telling R *'we have 30 possible factors, but not all of them will be present in each column'*, basicaly? And the warning comes when R tries to find every single possible value in all columns? Ps: Would you expand on what ```fct_expand()``` is doing here? I got it first for creating '8h', but now I don't see why it's still necessary? Could you go over it? – Larissa Cury Feb 10 '23 at 12:48
  • 1
    Yes that's it :). Every factor column has both a list of the possible levels and a list of the actual values. `fct_expand` increases all the possible levels by adding new ones given. `all_levels` above is a character vector of all possible levels - you can set what these are yourself but here I've just derived these from the data sample given. – Andy Baxter Feb 10 '23 at 12:54
  • (added a little demonstration of how this works in the code above) – Andy Baxter Feb 10 '23 at 12:59
  • Hi again, @Andy Baxter ! I'm getting this warning now, can you help me? ```! The `...` argument of `across()` is deprecated as of dplyr 1.1.0. Supply arguments directly to `.fns` through an anonymous function instead. # Previously across(a:b, mean, na.rm = TRUE) # Now across(a:b, \(x) mean(x, na.rm = TRUE))``` – Larissa Cury Feb 27 '23 at 11:09
  • 1
    Hi @LarissaCury - this would suggest going back to how you structured your code before rather than my option. So where you had `~ fct_collapse(., ...` you would change this to `\(x) fct_collapse(x, ...` and then the full list of levels to replace. Similarly the new lne `across(everything(), fct_expand, all_levels)` would become `across(everything(), \(x) fct_expand(x, all_levels)). The change it's asking for is that rather than pass the new arguments to the `across` function to let it then pass them to the inner function, you should specify them directly in the inner function instead. – Andy Baxter Feb 27 '23 at 11:24