data.frame 中组合的 R 基函数是 expand.grid。
expand.grid(df)
X1 X2 X3
1 a k e
2 b k e
3 NA k e
4 NA k e
... <lines removed for brevity>
61 a NA p
62 b NA p
63 NA NA p
64 NA NA p
您提供的示例数据的问题是它没有任何NA 值。创建data.frame 时,将文本“NA”放在引号中,这告诉R df 中的每一列都应包含一个字符向量,其元素等于字母“N”,后跟字母“A”,而不是比缺失数据的 R 值,NA(更准确地说,每一列都是一个 factor(枚举的 vector,请参阅 R 帮助中的 ?factor),其中包括一个级别“NA”(一个字符包含字母“N”后跟字母“A”的向量)而不是NA 的级别,但我离题了...查看 R 帮助中的factorsAsStrings 参数 -- ?data.frame -- 和?factors 下的主题以获取更多信息。)
底线:要使用包含NA 值的factors 列创建一个data.frame,不要在NA 周围使用引号:
df_NAs <- data.frame(X1=c("a", "b", NA, NA), X2=c("k", "l", "m", NA), X3=c("e", "t", "l", "p"))
现在,为了解决您的问题,我们需要在调用expand.grid 之前从df_NAs 的每一列中删除NA。记住 R data.frame 继承自 list(换句话说,R data.frame 是一个列表,其中列表的每个元素都包含 data.frame 的一列),我们可以使用lapply 将data.frame 的每一列传递给na.omit,即从向量中剥离NA 的R 函数。结果将作为向量列表返回:
list_NoNAs <- lapply(df_NAs, na.omit)
list_NoNAs
$X1
[1] a b
attr(,"na.action")
[1] 3 4
attr(,"class")
[1] "omit"
Levels: a b
$X2
[1] k l m
attr(,"na.action")
[1] 4
attr(,"class")
[1] "omit"
Levels: k l m
$X3
[1] e t l p
Levels: e l p t
通过查看列表中每个项目的第一行,您可以看到 NAs 已被删除。列表中每个元素的长度可以显示为:
lapply(list_NoNAs, length)
$X1
[1] 2
$X2
[1] 3
$X3
[1] 4
所以现在您有了不同长度的vectors 中的list,因为从data.frame 的每一列中删除了不同数量的NA。
幸运的是,expand.grid 不仅在 data.frames 上运行,而且在 lists 上运行;它不关心列表的每个元素是否有不同的长度。
foo = list(
letters = c("a", "b", "c"),
numbers = c(1, 2),
booleans = c(T)
)
expand.grid(foo)
letters numbers booleans
1 a 1 TRUE
2 b 1 TRUE
3 c 1 TRUE
4 a 2 TRUE
5 b 2 TRUE
6 c 2 TRUE
因此,要生成组合的data.frame,省略NAs:
df_combos <- expand.grid(lapply(df_NAs, na.omit))
df_combos
X1 X2 X3
1 a k e
2 b k e
3 a l e
4 b l e
5 a m e
6 b m e
7 a k t
8 b k t
9 a l t
10 b l t
11 a m t
12 b m t
13 a k l
14 b k l
15 a l l
16 b l l
17 a m l
18 b m l
19 a k p
20 b k p
21 a l p
22 b l p
23 a m p
24 b m p
现在我们需要从combos 的每一行生成一个字符串。要从值向量创建单个字符串,您可以使用:
paste(c("a", "b", "c"), collapse = "")
[1] "abc"
因此,要从df_combos 的每一行创建一个字符向量,您可以使用apply 将data.frame 的每一行发送到paste 函数:
apply(combos, 1, paste, collapse = "")
[1] "ake" "bke" "ale" "ble" "ame" "bme" "akt" "bkt" "alt" "blt" "amt" "bmt" "akl" "bkl" "all" "bll" "aml" "bml" "akp"
[20] "bkp" "alp" "blp" "amp" "bmp"
要在字母之间放置空格,请将collapse 参数更改为" ",如下所示:
apply(combos, 1, paste, collapse = " ")
[1] "a k e" "b k e" "a l e" "b l e" "a m e" "b m e" "a k t" "b k t" "a l t" "b l t" "a m t" "b m t" "a k l" "b k l"
[15] "a l l" "b l l" "a m l" "b m l" "a k p" "b k p" "a l p" "b l p" "a m p" "b m p"
如果你真的想在一行完全不可读的代码中完成所有这些,这里是:
apply(expand.grid(lapply(df_NAs, na.omit)), 1, paste, collapse = "")