如何总结保留所有列的数据框

jpm*_*m92 7 group-by aggregate r dplyr data-wrangling

考虑以下数据框:

\n
dummy_df <- tibble(\n  A=c("ABC", "ABC", "BCD", "CDF", "CDF", "CDF"),\n  B=c(0.25, 0.25, 1.23, 0.58, 0.58, 0.58),\n  C=c("lorem", "ipsum", "dolor", "amet", "something", "else"),\n  D=c("up", "up", "down", "down", "down", "down"),\n  E=c(132, 132, 243, 512, 512, 512),\n  F=c("m1", "m1", "m5", "m3", "m3", "m3"),\n  G=c("val", "val", "mur", "mad", "mad", "mad"),\n  H=c("grx", "grx", "bcn", "sal", "sal", "sal"),\n  I=c(1.68, 1.68, 2.31, 3.12, 3.12, 3.12),\n  J=c("p", "p", "f", "p", "p", "p"),\n  K=c(100, 100, 200, 143, 143, 143)\n)\n\n# A tibble: 6 \xc3\x97 11\n  A         B C         D         E F     G     H         I J         K\n  <chr> <dbl> <chr>     <chr> <dbl> <chr> <chr> <chr> <dbl> <chr> <dbl>\n1 ABC    0.25 lorem     up      132 m1    val   grx    1.68 p       100\n2 ABC    0.25 ipsum     up      132 m1    val   grx    1.68 p       100\n3 BCD    1.23 dolor     down    243 m5    mur   bcn    2.31 f       200\n4 CDF    0.58 amet      down    512 m3    mad   sal    3.12 p       143\n5 CDF    0.58 something down    512 m3    mad   sal    3.12 p       143\n6 CDF    0.58 else      down    512 m3    mad   sal    3.12 p       143\n
Run Code Online (Sandbox Code Playgroud)\n

读完本文后,我成功折叠了 C 列,以便将 A 列的每个唯一行值的值连接成一个字符串。

\n
dummy_df %>% group_by(A) %>% summarise(hits = toString(C), nhits=n())\n\n# A tibble: 3 \xc3\x97 3\n  A     hits                  nhits\n  <chr> <chr>                 <int>\n1 ABC   lorem, ipsum              2\n2 BCD   dolor                     1\n3 CDF   amet, something, else     3\n
Run Code Online (Sandbox Code Playgroud)\n

但是,我丢失了对我来说至关重要的所有其他列信息。如何在折叠 C 列时保留有关所有列的信息?理想情况下,无需对列名称进行硬编码即可完成此操作,因为列数可能会根据数据集而变化。

\n

我已阅读此内容,但显示的示例不会创建新变量,因此我无法使其工作。

\n

这就是我正在寻找的:

\n
# A tibble: 3 \xc3\x97 12\n  A     hits                  nhits     B D         E F     G     H         I J         K\n  <chr> <chr>                 <int> <dbl> <chr> <dbl> <chr> <chr> <chr> <dbl> <chr> <dbl>\n1 ABC   lorem, ipsum              2  0.25 up      132 m1    val   grx    1.68 p       100\n2 BCD   dolor                     1  1.23 down    243 m5    mur   bcn    2.31 f       200\n3 CDF   amet, something, else     3  0.58 down    512 m3    mad   sal    3.12 p       143\n
Run Code Online (Sandbox Code Playgroud)\n

r2e*_*ans 5

如果我们假设除C每个A组之外的所有字段都将包含重复值,那么我们可以这样做:

\n
dummy_df %>%\n  group_by(A) %>%\n  summarize(\n    nhits = n(),\n    across(where(is.character), ~ toString(unique(.))),\n    across(where(~ !is.character(.)), ~ unique(.))\n  ) %>%\n  ungroup()\n# # A tibble: 3 \xc3\x97 12\n#   A     nhits C                     D     F     G     H     J         B     E     I     K\n#   <chr> <int> <chr>                 <chr> <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl>\n# 1 ABC       2 lorem, ipsum          up    m1    val   grx   p      0.25   132  1.68   100\n# 2 BCD       1 dolor                 down  m5    mur   bcn   f      1.23   243  2.31   200\n# 3 CDF       3 amet, something, else down  m3    mad   sal   p      0.58   512  3.12   143\n
Run Code Online (Sandbox Code Playgroud)\n

在这种情况下,由于所有其他变量都在重复,所以一切都保持原样。但是,如果我们有可变性,那么我设置了一个捕获,其中字符串组合(与toString)并且不同的数字导致重复行。

\n
dummy_df$H[1] <- "GRX"\ndummy_df$K[1] <- 99\n %>%\n  group_by(A) %>%\n  summarize(\n    nhits = n(),\n    across(where(is.character), ~ toString(unique(.))),\n    across(where(~ !is.character(.)), ~ unique(.))\n  ) %>%\n  ungroup()\n# A tibble: 4 \xc3\x97 12\n  A     nhits C                     D     F     G     H        J         B     E     I     K\n  <chr> <int> <chr>                 <chr> <chr> <chr> <chr>    <chr> <dbl> <dbl> <dbl> <dbl>\n1 ABC       2 lorem, ipsum          up    m1    val   GRX, grx p      0.25   132  1.68    99\n2 ABC       2 lorem, ipsum          up    m1    val   GRX, grx p      0.25   132  1.68   100\n3 BCD       1 dolor                 down  m5    mur   bcn      f      1.23   243  2.31   200\n4 CDF       3 amet, something, else down  m3    mad   sal      p      0.58   512  3.12   143\n
Run Code Online (Sandbox Code Playgroud)\n

across函数迭代多个列。该where函数允许我们根据列的值对列进行子集化,对于character列,我们将应用toString,而对于其他列,我们将使用unique。这意味着字符串列永远不应该添加行,但非字符串可以。

\n

类似数字的列的替代方法是使用first(.)代替unique(.),它将按组默默地丢弃每列中除第一个值之外的所有值。使用相同的修改数据,我们会看到这一点,其中关键区别在于自从第一个值是 以来K已经丢弃了这些值。10099

\n
dummy_df %>%\n  group_by(A) %>%\n  summarize(\n    nhits = n(), \n    across(where(is.character), ~ toString(unique(.))),\n    across(where(~ !is.character(.)), ~ first(.))\n  ) %>%\n  ungroup()\n# # A tibble: 3 \xc3\x97 12\n#   A     nhits C                     D     F     G     H        J         B     E     I     K\n#   <chr> <int> <chr>                 <chr> <chr> <chr> <chr>    <chr> <dbl> <dbl> <dbl> <dbl>\n# 1 ABC       2 lorem, ipsum          up    m1    val   GRX, grx p      0.25   132  1.68    99\n# 2 BCD       1 dolor                 down  m5    mur   bcn      f      1.23   243  2.31   200\n# 3 CDF       3 amet, something, else down  m3    mad   sal      p      0.58   512  3.12   143\n
Run Code Online (Sandbox Code Playgroud)\n

如果您愿意,您也可以选择与字符串列一起使用first,这可以将逻辑简化为单个across

\n
dummy_df %>%\n  group_by(A) %>%\n  summarize(\n    nhits = n(),\n    across(everything(), ~ first(.))\n  ) %>%\n  ungroup()\n# # A tibble: 3 \xc3\x97 12\n#   A     nhits     B C     D         E F     G     H         I J         K\n#   <chr> <int> <dbl> <chr> <chr> <dbl> <chr> <chr> <chr> <dbl> <chr> <dbl>\n# 1 ABC       2  0.25 lorem up      132 m1    val   GRX    1.68 p        99\n# 2 BCD       1  1.23 dolor down    243 m5    mur   bcn    2.31 f       200\n# 3 CDF       3  0.58 amet  down    512 m3    mad   sal    3.12 p       143\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,我们已经丢失了H"grx"因为"GRX"是第一个)以及K的值100

\n

data.table最后一个代码块的变体可以简单地是:

\n
library(data.table)\nas.data.table(dummy_df)[, c(.(nhits = .N), lapply(.SD, first)), by = A]\n
Run Code Online (Sandbox Code Playgroud)\n

和基本的 R 演绎?也许不那么“漂亮”:-)

\n
Reduce(\n  function(a, b) merge(a, b, by = "A", all = TRUE), \n  list(\n    setNames(aggregate(C ~ A, dummy_df, FUN = length), c("A", "nhits")), \n    aggregate(C ~ A, dummy_df, FUN = toString),\n    aggregate(. ~ A, subset(dummy_df, select = -C), FUN = function(z) z[1])\n  )\n)\n#     A nhits                     C    B    D   E  F   G   H    I J   K\n# 1 ABC     2          lorem, ipsum 0.25   up 132 m1 val GRX 1.68 p  99\n# 2 BCD     1                 dolor 1.23 down 243 m5 mur bcn 2.31 f 200\n# 3 CDF     3 amet, something, else 0.58 down 512 m3 mad sal 3.12 p 143\n
Run Code Online (Sandbox Code Playgroud)\n