将 df 整数列拆分为 R 中的单个数字

Split df column of integers into individual digits in R

我有一个 df,其中一个变量是一个整数。我想将此列拆分为单独的数字。请参阅下面的示例

Group Number
A     456
B     3
C     18

Group Number Digit1 Digit2 Digit3
A     456    4      5      6
B     3      3      NA     NA
C     18     1      8      NA

我们可以使用 base R 中的 read.fwf。在 'Number' 列 (mx) 中找到 max 个字符 (nchar)。转换为characteras.character)后读取'Number'列,通过rep将1与mx相结合指定'widths'为1并赋值输出到数据

中的新 'Digit' 列
mx <- max(nchar(df1$Number))
df1[paste0("Digit", seq_len(mx))] <- read.fwf(textConnection(
             as.character(df1$Number)), widths = rep(1, mx))

-输出

df1
#  Group Number Digit1 Digit2 Digit3
#1     A    456      4      5      6
#2     B      3      3     NA     NA
#3     C     18      1      8     NA

数据

df1 <- structure(list(Group = c("A", "B", "C"), Number = c(456L, 3L, 
18L)), class = "data.frame", row.names = c(NA, -3L))

另一个基础 R 选项(我认为 @akrun 使用 read.fwf 的方法要简单得多)

cbind(
  df,
  with(
    df,
    type.convert(
      `colnames<-`(do.call(
        rbind,
        lapply(
          strsplit(as.character(Number), ""),
          `length<-`, max(nchar(Number))
        )
      ), paste0("Digit", seq(max(nchar(Number))))),
      as.is = TRUE
    )
  )
)

这给出了

  Group Number Digit1 Digit2 Digit3
1     A    456      4      5      6
2     B      3      3     NA     NA
3     C     18      1      8     NA

已更新 我意识到我可以使用 max 函数来计算每行中的字符限制,这样我就可以将它包含在我的 map2 函数中并保存一些代码行,这要归功于亲爱的 @ ThomasIsCoding.

library(dplyr)
library(tidyr)
library(purrr)
library(stringr)

df %>%
  rowwise() %>%
  mutate(map2_dfc(Number, 1:max(nchar(Number)), ~ str_sub(.x, .y, .y))) %>%
  unnest(cols = !c(Group, Number)) %>%
  rename_with(~ str_replace(., "\.\.\.", "Digit"), .cols = !c(Group, Number)) %>%
  mutate(across(!c(Group, Number), as.numeric, na.rm = TRUE))


# A tibble: 3 x 5
  Group Number Digit1 Digit2 Digit3
  <chr>  <dbl>  <dbl>  <dbl>  <dbl>
1 A        456      4      5      6
2 B          3      3     NA     NA
3 C         18      1      8     NA

数据

df <- tribble(
  ~Group, ~Number,
  "A",     456,
  "B",     3,
  "C",     18
)

两个基础 r 方法:

no_cols <- max(nchar(as.character(df1$Number)))

# Using `strsplit()`: 
cbind(df1, setNames(data.frame(do.call(rbind,
  lapply(strsplit(as.character(df1$Number), ""),
    function(x) { 
      length(x) <- no_cols
      x 
      }
    )
  )
), paste0("Digit", seq_len(no_cols))))

# Using `regmatches()` and `gregexpr()`:
cbind(df1, setNames(data.frame(do.call(rbind, 
  lapply(regmatches(df1$Number, gregexpr("\d", df1$Number)),
    function(x) {
      length(x) <- no_cols
      x
      }
    )
  )
), paste0("Digit", seq_len(no_cols))))

使用splitstackshape::cSplit

splitstackshape::cSplit(df, 'Number', sep = '', stripWhite = FALSE, drop = FALSE)

#   Group Number Number_1 Number_2 Number_3
#1:     A    456        4        5        6
#2:     B      3        3       NA       NA
#3:     C     18        1        8       NA