因素有不同的层次,但我不明白为什么

Factors have different levels but I don't understand why

提问人:Ollie 提问时间:11/14/2023 最后编辑:Ollie 更新时间:11/15/2023 访问量:43

问:

我正在使用 Bradley-Terry 模型对网球比赛的结果进行建模,并遇到了以下错误。当我运行时:

library(BradleyTerry2)

matches <- read.csv("data/matches.csv")
model <- BTm(cbind(wins1,
                   wins2),
             player1, player2, data=matches)
model

我收到错误消息:

Error in Diff(player1, player2, formula, id, data, separate.ability, refcat,  : 
  'player1$..' and 'player2$..' must be factors with the same levels

数据帧“matches”具有此格式(小型可重现示例)。

玩家 1 玩家2 胜利1 胜利2
阿加西 费德勒 0 6
阿加西 休伊特 1 0
阿加西 罗迪克 1 0
费德勒 亨曼 3 1
费德勒 休伊特 9 0
费德勒 罗迪克 5 0
亨曼 休伊特 0 2
亨曼 罗迪克 1 1
休伊特 罗迪克 3 2

...等等。出现在 player1 中的任何名称都将出现在 player2 中。

我不明白为什么 player1 和 player2 的因子有不同的级别?我尝试将它们设置为使用 ,但这不起作用。我还尝试删除和使用等作为函数的参数,但这也不起作用。现在我有点卡住了,所以欢迎任何想法!谢谢:)as.factordata=matchesmatches$wins1BTm

R 因子

评论

2赞 Mark 11/14/2023
也许数据集中有一个玩家只出现过一次?考虑将两者的级别设置为两者的唯一名称的组合向量
1赞 MrFlick 11/14/2023
如果包含一个简单的可重现示例和示例输入,则更容易为您提供帮助,该示例输入可用于测试和验证可能的解决方案。在您的示例中,“Roger Federer”位于 player1 中,但不在 player2 中,这会导致问题。
0赞 moodymudskipper 11/14/2023
check 和 .也许你可以直接转换为字符,它就会起作用,或者将这些级别合并,并在这两个变量上使用级别参数levels(df$player1)levels(df$player2)factor()
0赞 PGSA 11/14/2023
你能包括 和 的输出吗?此外,该函数是否要求它们以相同的顺序具有相同的级别?levels(matches$player1)levels(matches$player2)
0赞 Ollie 11/14/2023
@PGSA是的,看起来每个的 levels() 都不同,所以我想我用于生成数据文件的代码中存在一个错误。我来看看!

答:

0赞 Rui Barradas 11/15/2023 #1

看看你在第一列和第二列中有什么。
因子在内部编码为从 1 开始的连续整数。下面我每个人为了得到他们的内部代表。
unclass

  • player1有两个值,1 和 2;
  • player2有两个值,1 和 2;
  • 在级别中为 1st,其值为 1player1"Rafael Nadal";
  • 但是在级别是 2 号,它的值是 2player2"Rafael Nadal"

这是因为每一列都是一个单独的因子,与另一列无关。

lapply(matches[1:2], unclass)
#> $player1
#> [1] 2 2 1
#> attr(,"levels")
#> [1] "Rafael Nadal"  "Roger Federer"
#> 
#> $player2
#> [1] 2 1 1
#> attr(,"levels")
#> [1] "Andy Murray"  "Rafael Nadal"

创建于 2023-11-14

解决方案是获取所有列的所有唯一值,并在创建因子时将这些唯一值用作级别。

在后面的代码中,第一条指令将所有唯一值作为字符串获取。然后创建因子列,并将这些字符串作为其级别。

lvls <- matches[1:2] |> unlist() |> as.character() |> unique()
matches[1:2] <- lapply(matches[1:2], factor, levels = lvls)

# check that now "Rafael Nadal" is always value 2
lapply(matches[1:2], unclass)
#> $player1
#> [1] 1 1 2
#> attr(,"levels")
#> [1] "Roger Federer" "Rafael Nadal"  "Andy Murray"  
#> 
#> $player2
#> [1] 2 3 3
#> attr(,"levels")
#> [1] "Roger Federer" "Rafael Nadal"  "Andy Murray"

创建于 2023-11-14


数据

matches <- structure(list(
  player1 = structure(c(2L, 2L, 1L), levels = c("Rafael Nadal", "Roger Federer"), class = "factor"), 
  player2 = structure(c(2L, 1L, 1L), levels = c("Andy Murray", "Rafael Nadal"), class = "factor"), 
  wins1 = c(3L, 5L, 4L), wins2 = c(2L, 2L, 3L)), 
  class = "data.frame", row.names = c(NA, -3L))

创建于 2023-11-14


编辑

同时,问题中的示例数据集已更改。除了对球员姓名的引用外,上面的代码仍然有效并解决了问题。

0赞 Ollie 11/15/2023 #2

在原始帖子评论的大力帮助下,它现在已经解决了......只需要确保 players1 和 players2 列只包含相同的玩家(这可能意味着在数据文件中切换某个回合),然后使用 around 和 .as.factor()player1player2