【问题标题】:Combining many columns in R at once一次组合R中的许多列
【发布时间】:2018-02-07 17:29:33
【问题描述】:

我有一个类似于以下的数据框:

A1U_sweet  A2F_dip  A3U_bbq  C1U_sweet  C2F_dip  C3U_bbq
1          2        1        NA         NA       NA
NA         NA       NA       4          1        2
2          4        7        NA         NA       NA

我想创建额外的列来组合 A 值和 C 值。生成的数据框将包含看起来像 B1U_sweet 和 B2F_dip 的列。

A1U_sweet  A2F_dip  A3U_bbq  C1U_sweet  C2F_dip  C3U_bbq  B1U_sweet  B2F_dip
1          2        1        NA         NA       NA       1          2
NA         NA       NA       4          1        2        4          1
2          4        7        NA         NA       NA       2          4

有没有一种方法可以让我创建这些额外的列,而无需将 A 列和 C 列一一合并?在过去,我将它们单独组合在一起,但如果有类似循环的东西匹配列 A1 和 C1、A2 和 C2 等,那就太好了。有 20 个“A”列和 20 个“C”列我想合并成“B”列。

编辑:解决方案是这里公认的答案:Combining columns in R based on matching beginnings of column title names

【问题讨论】:

  • 我不确定您是如何“组合”这些列的,但您可以尝试:res <- mapply(sum, df[, 1:3], df[, 4:6], na.rm=T)。如果有一种聪明的方法可以解析出名称,则将 1:3 和 4:6 替换为名称的字符向量。现在,grep('A', colnames(df))grep('C', colnames(df)) 有效。

标签: r loops for-loop


【解决方案1】:

你可以这样做:

types <- grep('^A', names(df)) ## Get all "A" patterns
types <- substr(types, 2, Inf) ## Remove the "A"
for (tp in types) {
  aa <- df[[paste0('A', tp)]] ## "A" column
  cc <- df[[paste0('C', tp)]] ## "C" column
  df[[paste0('B', tp)]] <- ifelse(is.na(aa), aa, cc)
}

编辑:如果您的 df 中的其他一些列以 A 开头,您可以尝试以下 3 件事之一:

  1. 首先从 df 中删除它们

  2. 不要 grep 类型,而是手动输入它们(例如 types &lt;- c("1U_sweet", ...)

  3. 如果您的类型遵循特定模式,您可以将 grep 中的正则表达式更改为 "^A[0-9][0-9][A-Z]_[a-z]+"

【讨论】:

  • 如果数据框中还有其他以 A 或 C 开头的列,是否有问题?例如,我有一个 Age 列和一个 Comments 列,我担心它们会干扰。
  • "^A[0-9][A-Z]_[a-z]+" 中的每个组件是什么意思?
  • 表示它以大写A开头,然后是数字,然后是任意一个大写字母,然后是下划线,然后是一个或多个小写字母
  • 当前 [0-9] 的某些值会增加到 20。例如,有以 A13F_cr 和 A20U_kj 开头的列名。我尝试将 [0-9] 更改为 [0-20] 但它不起作用。我该如何解释?
  • 另外,is.na(a) 中的“a”触发了错误。 “找不到对象‘a’”。有谁知道为什么会这样?
【解决方案2】:

不使用循环的 dplyr 方法:

df = read.table(text = "
A1U_sweet  A2F_dip  A3U_bbq  C1U_sweet  C2F_dip  C3U_bbq
1          2        1        NA         NA       NA
NA         NA       NA       4          1        2
2          4        7        NA         NA       NA
", header=T)

library(tidyverse)

df %>%
  mutate(row_id = row_number()) %>%
  gather(col,value,-row_id) %>%
  mutate(col1 = substr(col, 1, 1),
         col2 = substr(col, 2, nchar(col))) %>%
  group_by(row_id, col2) %>%
  summarise(new_value = unique(value[!is.na(value)])) %>%
  ungroup() %>%
  mutate(col2 = paste0("B",col2)) %>%
  spread(col2,new_value) %>%
  bind_cols(df) %>%
  select(-row_id, -B3U_bbq)

# # A tibble: 3 x 8
#   B1U_sweet B2F_dip A1U_sweet A2F_dip A3U_bbq C1U_sweet C2F_dip C3U_bbq
#       <int>   <int>     <int>   <int>   <int>     <int>   <int>   <int>
# 1         1       2         1       2       1        NA      NA      NA
# 2         4       1        NA      NA      NA         4       1       2
# 3         2       4         2       4       7        NA      NA      NA

【讨论】:

  • 如果您在尝试将其应用于完整数据集时发现任何错误,请告诉我,我将能够对其进行更新。根据您的示例,我假设列名将始终从 A 或 C 开始,并且在每一行的 sweet、dip 等中总会有一个非 NA 值。
  • 您介意解释一下每一行的作用吗?此外,我的实际数据框中的列名不是示例中的第 1 列、第 2 列等。 A 名称从第 19 列开始,C 名称从第 39 列开始(有 20 个 A 名称和 20 个对应的 C 名称)。我会修改什么来解决这个问题?
猜你喜欢
  • 2014-08-27
  • 1970-01-01
  • 2017-12-20
  • 1970-01-01
  • 1970-01-01
  • 2011-01-21
  • 1970-01-01
  • 2016-05-12
  • 1970-01-01
相关资源
最近更新 更多