Разделение столбца символов на две части и повторение - PullRequest
0 голосов
/ 16 января 2019

Это данные, которые у меня есть,

v11 <- c("00240031", "00310028")
v12 <- c("00000000", "00000000")
v13 <- c("00310064", "00180058")
data <- data.frame(v11, v12, v13)
data <- lapply(data, as.character)
testdata <- as.data.frame(data, stringsAsFactors = F)
testdata[testdata == '0'] <- '000000000'
testdata

Я хочу разбить каждый столбец (начиная с v11 до v99) на два столбца. Я использую substr, чтобы разделить это так для первого столбца,

transform(v11, v11_a = substr(v11, 1, 4), v11_b = substr(v11, 5, 8))

    X_data v11_a v11_b
1 00240031  0024  0031
2 00310028  0031  0028

Выглядит хорошо, кроме столбца X_data. Я не хочу, чтобы это было на выходе. Есть ли лучший способ сделать это?

tidyr::separate не будет применимо, так как мои данные относятся к типу символов?

v11 %>% separate(v11, into = c('v11_a', 'v11_b'), sep = 4)
Error in UseMethod("separate_") : 
  no applicable method for 'separate_' applied to an object of class "character"

Во-вторых, как я могу повторить процесс для последующих столбцов (например, с v11 по v99)?

В идеале, после разбиения и последующего преобразования в числовой тип мои окончательные данные должны выглядеть следующим образом:

> dataf
  v11_a v11_b v12_a v12_b v13_a v13_b
1    24    31     0     0    31    64
2    31    28     0     0    18    58

Комментарий:

Удивительно, как быстро вы предлагаете удивительные решения. Спасибо вам всем.

Ответы [ 3 ]

0 голосов
/ 16 января 2019

Вот идея использования очень удобных для таких операций library(splitstackshape),

library(splitstackshape)

cSplit(setDT(testdata)[, lapply(.SD, function(i) gsub("(.{4})", "\\1 ", i))], names(testdata), sep = ' ')
#   v11_1 v11_2 v12_1 v12_2 v13_1 v13_2
#1:    24    31     0     0    31    64
#2:    31    28     0     0    18    58
0 голосов
/ 16 января 2019

Некоторые играют в data.table и повторно используют существующую логику substr():

library(data.table)
setDT(testdata)
cols <- paste0("v", 11:13)
new_cols <- paste0(rep(cols, 2), rep(c("a", "b"), each = length(cols)))
extra <- function(x) substr(x, 1, 4)
extrb <- function(x) substr(x, 5, 8)
testdata[, (new_cols) := c(lapply(.SD, extra), lapply(.SD, extrb)), .SDcols = cols]

> testdata
        v11      v12      v13 v11a v12a v13a v11b v12b v13b
1: 00240031 00000000 00310064 0024 0000 0031 0031 0000 0064
2: 00310028 00000000 00180058 0031 0000 0018 0028 0000 0058
0 голосов
/ 16 января 2019

В base R это может быть сделано путем циклического перемещения по столбцам, замены нулей между ненулевыми значениями с разделителем ,, считывания в data.frame (read.table) и cbind list наборов данных

lst1 <- lapply(testdata, function(x) {
      x1 <- read.table(text = sub("(?<=[1-9])0+", ",", x, perl = TRUE),
             header = FALSE, sep=",", col.names = c('a', 'b'), fill = TRUE)
      replace(x1, is.na(x1), 0)})
do.call(cbind, lst1)
#   v11.a v11.b v12.a v12.b v13.a v13.b
#1    24    31     0     0    31    64
#2    31    28     0     0    18    58

Это также можно сделать с помощью tidyverse, сначала gather, перейдя в «длинный» формат, затем выполнить separate ion и, наконец, spread вернуть его в «широкий» формат

library(tidyverse)
gather(testdata) %>%
    separate(value, into = c('a', 'b'), sep=4, convert = TRUE) %>% 
    gather(key1, val, a:b) %>%
    unite(key, key, key1, sep="_") %>% 
    group_by(key) %>% 
    mutate(ind = row_number()) %>% 
    spread(key, val) %>%
    select(-ind)
# A tibble: 2 x 6
#  v11_a v11_b v12_a v12_b v13_a v13_b
#  <int> <int> <int> <int> <int> <int>
#1    24    31     0     0    31    64
#2    31    28     0     0    18    58

Или другой вариант - использовать summarise_all с read.table

testdata %>%
   summarise_all(funs(list(read.table(text =sub("^(....)", "\\1 ", .),
             header = FALSE)))) %>%
   unnest
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...