Reputation: 1
I am trying to run the following code using the panelperf function from the SensoMineR package:
panelperf<-panelperf(data,formul="~Product+Panelist+rep+Product:Panelist+Product:rep+Panelist:rep", firstvar=4)
My data frame consists on: column 1: panelists, filled with names of panelists column 2: product: filled with the names of the products column 3: rep , the replicate of the product measured column 4 till the end: variables that were measured (light fruit, dark fruit, alcohol, sourness, etc) All my variables are dbl
But I get the following error when running the function:
Error in `contrasts<-`(`*tmp*`, value = contr.funs[1 + isOF[nn]]) : contrasts can be applied only to factors with 2 or more levels In addition: Warning messages: 1: In xtfrm.data.frame(x) : cannot xtfrm data frames 2: In xtfrm.data.frame(x) : cannot xtfrm data frames 3: In xtfrm.data.frame(x) : cannot xtfrm data frames
sapply(lapply(data, unique), length)
Product Panelist rep Lightfruit Darkfruit Applepear Citrus DryFruit Nutty Vegetables Earthy Floral
13 12 2 87 83 72 67 76 69 76 67 66
Woddy hgt Chemical Chocolate Honey Cheesy Alcohol Overallaroma Astringent Sour Hot Viscocity
62 64 80 57 65 69 86 85 88 85 85 83
Sweet Bitter
87 86
So none of the variables has only 2 levels as the error suggests
I have been reading answers about this error, but either the answers dont apply to my case or, as a non very experienced R user, I do not follow what they suggest.
I would appreciate your help a lot!
Thank you!
And let me know if you need more information!
Upvotes: 0
Views: 70
Reputation: 887118
The code to check the factor levels can be
i1 <- sapply(data, \(x) is.factor(x) && nlevels(x) > 1)
i2 <- !sapply(data, is.factor)
data1 <- data[i1|i2]
Here is an example that shows the issue - with the data having nlevels for factor > 1, it works
library(SensoMineR)
data(chocolates)
res <- panelperf(sensochoc, firstvar = 5, formul = "~Product+Panelist+
Session+Product:Panelist+Session:Product+Panelist:Session")
> str(res)
List of 4
$ p.value : num [1:14, 1:6] 8.85e-14 6.44e-08 1.75e-28 3.74e-40 1.18e-22 ...
..- attr(*, "dimnames")=List of 2
.. ..$ : chr [1:14] "CocoaA" "MilkA" "CocoaF" "MilkF" ...
.. ..$ : chr [1:6] "Product " "Panelist " "Session " "Product:Panelist" ...
$ variability: num [1:14, 1:6] 0.139 0.103 0.397 0.532 0.267 ...
..- attr(*, "dimnames")=List of 2
.. ..$ : chr [1:14] "CocoaA" "MilkA" "CocoaF" "MilkF" ...
.. ..$ : chr [1:6] "Product " "Panelist " "Session " "Product:Panelist" ...
$ res : num [1:14, 1] 1.87 1.89 1.41 1.47 1.63 ...
..- attr(*, "dimnames")=List of 2
.. ..$ : chr [1:14] "CocoaA" "MilkA" "CocoaF" "MilkF" ...
.. ..$ : chr "stdev residual"
$ r2 : num [1:14, 1] 0.673 0.761 0.846 0.882 0.862 ...
..- attr(*, "dimnames")=List of 2
.. ..$ : chr [1:14] "CocoaA" "MilkA" "CocoaF" "MilkF" ...
.. ..$ : chr "r2"
> str(sensochoc)
'data.frame': 348 obs. of 18 variables:
$ Panelist : Factor w/ 29 levels "1","2","3","4",..: 1 1 1 1 1 1 2 2 2 2 ...
$ Session : Factor w/ 2 levels "1","2": 1 1 1 1 1 1 1 1 1 1 ...
$ Rank : Factor w/ 6 levels "1","2","3","4",..: 1 6 3 5 2 4 1 4 3 5 ...
$ Product : Factor w/ 6 levels "choc1","choc2",..: 6 3 2 1 4 5 4 3 6 2 ...
$ CocoaA : int 7 6 8 7 8 7 6 4 5 5 ...
$ MilkA : int 6 7 6 8 5 5 1 2 1 2 ...
$ CocoaF : int 6 2 5 8 4 3 8 3 8 8 ...
$ MilkF : int 5 7 4 3 4 5 1 4 1 1 ...
$ Caramel : int 5 8 7 3 4 6 0 0 0 0 ...
$ Vanilla : int 3 4 4 2 4 2 0 0 0 0 ...
$ Sweetness : int 7 7 5 4 5 5 1 5 1 0 ...
$ Acidity : int 2 2 5 7 6 4 0 0 0 0 ...
$ Bitterness : int 4 2 6 8 6 7 3 0 3 6 ...
$ Astringency: int 5 3 6 6 4 4 0 0 0 0 ...
$ Crunchy : int 8 3 7 3 6 6 8 4 6 8 ...
$ Melting : int 3 8 5 2 3 6 5 8 2 2 ...
$ Sticky : int 4 6 4 3 7 4 0 3 1 4 ...
$ Granular : int 3 5 3 5 3 7 0 1 1 0 ...
If we change the 'Session' level 2 to NA (which have only 2 levels), it shows the error
levels(sensochoc$Session)[2] <- NA
res1 <- panelperf(sensochoc, firstvar = 5, formul = "~Product+Panelist+
Session+Product:Panelist+Session:Product+Panelist:Session")
Error in `contrasts<-`(`*tmp*`, value = contr.funs[1 + isOF[nn]]) :
contrasts can be applied only to factors with 2 or more levels
With OP's code, it still shows the data to be having more than 1 level because unique
returns NA
as well if present and thus the length
will include the NA element, here it is 2 in total
> sapply(lapply(sensochoc, unique), length)
Panelist Session Rank Product CocoaA MilkA CocoaF MilkF Caramel Vanilla Sweetness Acidity
29 2 6 6 11 11 11 11 11 10 11 11
Bitterness Astringency Crunchy Melting Sticky Granular
11 11 11 11 11 11
where as with the specific code in this post, nlevels
remove the NA
an return only the count of non-NA levels
i1 <- sapply(sensochoc, \(x) is.factor(x) && nlevels(x) > 1)
i2 <- !sapply(sensochoc, is.factor)
names(sensochoc)[i1]
[1] "Panelist" "Rank" "Product"
names(sensochoc)[sapply(sensochoc, is.factor)]
[1] "Panelist" "Session" "Rank" "Product"
Session
is omitted. We may need to change the formula to omit the terms that have Session
Upvotes: 0