Skip to content

Commit 1a3d82a

Browse files
author
hornik
committed
Have interaction(drop = TRUE) compute used levels directly instead
of dropping unused levels from all possible levels (PR#18276). git-svn-id: https://svn.r-project.org/R/trunk@87735 00db46b3-68df-0310-9c12-caf00c1e9a41
1 parent 051e6cb commit 1a3d82a

File tree

1 file changed

+34
-23
lines changed

1 file changed

+34
-23
lines changed

src/library/base/R/interaction.R

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# File src/library/base/R/interaction.R
22
# Part of the R package, https://www.R-project.org
33
#
4-
# Copyright (C) 1995-2013 The R Core Team
4+
# Copyright (C) 1995-2025 The R Core Team
55
#
66
# This program is free software; you can redistribute it and/or modify
77
# it under the terms of the GNU General Public License as published by
@@ -29,39 +29,50 @@ interaction <- function(..., drop = FALSE, sep = ".", lex.order = FALSE)
2929
narg <- length(args)
3030
}
3131
for(i in narg:1L) {
32-
f <- as.factor(args[[i]])[, drop = drop]
33-
l <- levels(f)
34-
if1 <- as.integer(f) - 1L
32+
x <- as.factor(args[[i]])[, drop = drop]
33+
ax <- as.integer(x) - 1L
34+
lx <- levels(x)
3535
if(i == narg) {
36-
ans <- if1
37-
lvs <- l
36+
ay <- ax
37+
ly <- lx
3838
} else {
39+
nx <- length(lx)
40+
ny <- length(ly)
3941
if(lex.order) {
40-
ll <- length(lvs)
41-
ans <- ans + ll * if1
42-
lvs <- paste(rep(l, each = ll), rep(lvs, length(l)), sep=sep)
42+
ay <- ay + ny * ax
43+
if(drop) {
44+
az <- sort(unique(ay))
45+
ly <- paste(lx[az %/% ny + 1L], ly[az %% ny + 1L],
46+
sep = sep)
47+
ay <- match(ay, az) - 1L
48+
} else {
49+
ly <- paste(rep(lx, each = ny), rep(ly, nx),
50+
sep = sep)
51+
}
4352
} else {
44-
ans <- ans * length(l) + if1
45-
lvs <- paste(rep(l, length(lvs)),
46-
rep(lvs, each = length(l)), sep=sep)
53+
ay <- ay * nx + ax
54+
if(drop) {
55+
az <- sort(unique(ay))
56+
ly <- paste(lx[az %% nx + 1L], ly[az %/% nx + 1L],
57+
sep = sep)
58+
ay <- match(ay, az) - 1L
59+
} else {
60+
ly <- paste(rep(lx, ny), rep(ly, each = nx),
61+
sep = sep)
62+
}
4763
}
48-
while(j <- anyDuplicated(lvs)) {
64+
while(j <- anyDuplicated(ly)) {
4965
## If levels at positions i and j > i are the same, we
5066
## need to drop the one at j, change the code for that
5167
## level to the code for level i, and decrease all codes
5268
## beyond the code for level j by one.
53-
i <- match(lvs[j], lvs)
54-
lvs <- lvs[-j]
69+
i <- match(ly[j], ly)
70+
ly <- ly[-j]
5571
j <- j - 1L
56-
ans[ans == j] <- i - 1L
57-
ans[ans > j] <- ans[ans > j] - 1L
58-
}
59-
if(drop) {
60-
olvs <- lvs
61-
lvs <- lvs[sort(unique(ans+1L))]
62-
ans <- match(olvs[ans+1L], lvs) - 1L
72+
ay[ay == j] <- i - 1L
73+
ay[ay > j] <- ay[ay > j] - 1L
6374
}
6475
}
6576
}
66-
structure(as.integer(ans+1L), levels=lvs, class = "factor")
77+
structure(as.integer(ay + 1L), levels = ly, class = "factor")
6778
}

0 commit comments

Comments
 (0)