【问题标题】:Combinations of character cells in a data.frame with some conditions具有某些条件的 data.frame 中字符单元格的组合
【发布时间】:2019-07-29 21:27:30
【问题描述】:

我希望有人可以帮助我解决这个问题。 想象一下下面的字符数据框:

df <- data.frame(X1=c("a", "b"), X2=c("k", "l"))

df

  X1 X2
1  a  k
2  b  l

我想获得列单元格之间的所有可能组合。

在这种情况下:

阿克

一个

bk

b l

我的问题是我不想指定我有多少列和行,并且代码应该忽略 NA(缺失值)。编辑:所以在三列中必须有三个元素。

df <- data.frame(X1=c("a", "b", "NA", "NA"), X2=c("k", "l", "m", "NA"), X3=c("e", "t", "l", "p"))

df

  X1 X2 X3
1  a  k  e
2  b  l  t
3 NA  m  l
4 NA NA  p

另一个问题是,我不希望组合长度小于列数。 因此,请确定一些适合的示例:

一言为定

一乐

b l t

一些不适合的例子:

一个

NA NA p

结果应保存在字符向量中。向量中的每个元素都应该是一个组合。

也许有人有一个想法,或者也许已经有一个线程可以帮助我,但我没有找到一些。

我尝试了不同的功能,例如 combn() 或 combine() 但要么它不适合问题,要么我以错误的方式使用它。

编辑: 第二个df的整个假定输出:

一言为定

一言为定

一口一口

一个 k p

一乐

一秒

一拉一拉

a lp

一个人

一秒

一米

a 米 p

b k e

b k t

b k l

b k p

b l e

b l t

b l l

b l p

b 我

b m t

b m l

b m p

我希望我没有犯错。

【问题讨论】:

  • 我对不同阶段的解释有点困惑。您能否提供所提供数据集df完整预期输出?
  • 我添加了整个假定的输出并稍微改变了条件。我在这里犯了一些错误,抱歉造成混乱:(但感谢您在这里的帮助
  • 为什么没有像a m e 这样的行?
  • 抱歉,这正是我想自动执行此操作的原因,我犯了一个错误。我希望解释和示例中不再有任何错误:)

标签: r dataframe


【解决方案1】:

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 的一列),我们可以使用lapplydata.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 的每一行创建一个字符向量,您可以使用applydata.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 = "")

【讨论】:

    【解决方案2】:

    另一种解决方案:

    > df <- data.frame(X1 = c("a", "b", "NA", "NA"), X2 = c("k", "l", "m", "NA"), X3 = c("e", "t", "l", "p"), stringsAsFactors = FALSE)
    > df[df == "NA"] <- NA
    > na.omit(object = rev(x = expand.grid(rev(x = df))))
       X1 X2 X3
    1   a  k  e
    2   a  k  t
    3   a  k  l
    4   a  k  p
    5   a  l  e
    6   a  l  t
    7   a  l  l
    8   a  l  p
    9   a  m  e
    10  a  m  t
    11  a  m  l
    12  a  m  p
    17  b  k  e
    18  b  k  t
    19  b  k  l
    20  b  k  p
    21  b  l  e
    22  b  l  t
    23  b  l  l
    24  b  l  p
    25  b  m  e
    26  b  m  t
    27  b  m  l
    28  b  m  p
    

    如果你需要一个字符向量,你可以使用paste,就像@Geoffrey Poole 建议的那样。

    【讨论】:

    • 也谢谢你:)
    • 哎呀。我的回答比需要的更复杂。 Yarnabrina 的解决方案更加优雅,尽管该解决方案的最后一行可能只是 na.omit(expand.grid(df)))。如果 Yarnabrina 的解决方案是 expand.grid 可以制作一个非常大的数据框,那么唯一的缺点是 df 有很多案例和/或列。通过首先从列中删除 NA 值,组合的结果数据框保持尽可能小。
    • @GeoffreyPoole na.omit(expand.grid(df))) 返回行的顺序与 OP 发布的顺序不同。这就是我反转两次的原因。我不确定如何通过首先省略 NA 值来获得 OP 的订单。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-03
    • 1970-01-01
    • 1970-01-01
    • 2014-01-16
    • 2013-02-01
    • 2018-06-13
    • 1970-01-01
    相关资源
    最近更新 更多