Вставить элементы от x до y из списка вместе

Я читаю огромный набор данных, используя fread() из data.table. Проблема в том, что количество полей (разделитель = ;) различается в каждой строке. Меня в основном интересуют первые 5 столбцов, но я также хочу увидеть содержимое столбца с 6-го по нth.

образец данных
Я читаю данные с data.table::fread() с sep = "", чтобы читать целыми строками.

DT <- data.table::fread("1;2;3;4;5;6
            1;2;3;4;5;6;7;8
            1;2;3;4;5", sep = "", header = FALSE, col.names = "text" )

#              text
#1:     1;2;3;4;5;6
#2: 1;2;3;4;5;6;7;8
#3:       1;2;3;4;5

код до сих пор
Первые пять столбцов присутствуют во всех строках, и я могу легко получить их с помощью tstrsplit():

DT[, c("v1", "v2", "v3", "v4", "v5") := tstrsplit( text , ";")[1:5] ][]

#               text v1 v2 v3 v4 v5
# 1:     1;2;3;4;5;6  1  2  3  4  5
# 2: 1;2;3;4;5;6;7;8  1  2  3  4  5
# 3:       1;2;3;4;5  1  2  3  4  5

мой вопрос
Я хочу поместить все поля после пятой (или все после пятой точки с запятой) в столбец с именем v6, чтобы результат выглядел так:

desired_output <- DT[, v6 := c( "6", "6;7;8", NA_character_) ]
#               text v1 v2 v3 v4 v5    v6
# 1:     1;2;3;4;5;6  1  2  3  4  5     6
# 2: 1;2;3;4;5;6;7;8  1  2  3  4  5 6;7;8
# 3:       1;2;3;4;5  1  2  3  4  5  <NA>

примечание: длина текста между ; ; может варьироваться, поэтому не всегда один, а также не всегда числовой.

Мои производственные данные содержат более 1 млн строк, поэтому чем быстрее решение, тем лучше.

В вашем наборе данных 1: 5 в «тексте» является обычным явлением. Это ты проверяешь? Кроме того, имеет ли значение порядок элементов, скажем, 1:5 в первых рядах, 2, 4, 1, 3 во втором ряду или 4, 4, 1, 2 в третьем ряду?

akrun 28.03.2019 18:27

Не могли бы вы уточнить, почему вы хотите, чтобы «лишние» строки были объединены. Если вы можете жить с отдельными столбцами (кажется более «аккуратным»), используйте sep = ";" и fill = TRUE в fread. Вот и все.

Henrik 28.03.2019 18:37

@henrik Я пытался, но это: fread( "./stuff.log", header = FALSE, sep = "\t", fill = TRUE ) все еще выдает ошибку в моих производственных данных, Stopped early on line 201. Expected 8 fields but found 9..

Wimpel 28.03.2019 18:42

@akrun the 1;2;3;4;5 - это просто образец текста с образцами разделителей.. числа могут быть любыми, разделители в моих производственных данных на самом деле являются вкладками (\t). Он хотел проиллюстрировать, что каждая строка имеет как минимум пять полей (а некоторые еще пару).

Wimpel 28.03.2019 18:43

У @Henrik, похоже, были проблемы здесь: github.com/Rdatatable/data.table/issues/2727

Wimpel 28.03.2019 18:54
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
5
114
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Вариантом может быть separate с параметром extra, указанным как «объединить».

library(tidyverse)
n <- 6
DT %>% 
   separate(text, into = paste0("v", seq_len(n)), extra = "merge",
     convert = TRUE, remove = FALSE)
#              text v1 v2 v3 v4 v5    v6
#1:     1;2;3;4;5;6  1  2  3  4  5     6
#2: 1;2;3;4;5;6;7;8  1  2  3  4  5 6;7;8
#3:       1;2;3;4;5  1  2  3  4  5  <NA>

это работает, спасибо! .. хотя я предпочитаю (быстрое) решение base или data.table, так как мои производственные данные довольно велики (я отредактирую это, чтобы задать вопрос)

Wimpel 28.03.2019 18:24

@Wimpel Что касается логики, вы проверяете количество элементов или совпадений в каждой строке?

akrun 28.03.2019 18:26

количество «полей».. ; — это разделитель, указывающий на новое поле. Я просто хочу прочитать текст в файле, но количество столбцов зависит от строки, и fread() не может справиться с этим правильно за один раз, даже если fill = TRUE (я еще не нашел правильных настроек).

Wimpel 28.03.2019 18:46
Ответ принят как подходящий

Вот вариант с data.table и stringr. Не уверен, что это быстрее, чем separate

library(stringr)

DT[,  paste0('col', 1:5) := tstrsplit(text, ';')[1:5]] # or tstrsplit(str_extract(text, '(\\d+;){4}\\d+'), ';')
DT[, col6 :=  str_remove(text, '(\\d+;){5}|(\\d+;){4}\\d+')]

DT
#               text col1 col2 col3 col4 col5  col6
# 1:     1;2;3;4;5;6    1    2    3    4    5     6
# 2: 1;2;3;4;5;6;7;8    1    2    3    4    5 6;7;8
# 3:       1;2;3;4;5    1    2    3    4    5      

Я приблизился к тому, что вы хотите, используя appendtransposelapply и paste0 вместе взятые. Не уверен, как он сравнивается с другими, хотя.

DT[, c("v1", "v2", "v3", "v4", "v5", "v6") := append(tstrsplit(text , ";")[1:5],
                                                     transpose(lapply(transpose(tstrsplit(text, ";")[-c(1:5)]), paste0, collapse=';')))][]

Это также можно изменить, чтобы сделать это, используя концепцию цепочки для лучшего чтения.

DT[, c("v1", "v2", "v3", "v4", "v5") := tstrsplit(text , ";")[1:5]
   ][, v6 := transpose(lapply(transpose(tstrsplit(text, ";")[-c(1:5)]), paste0, collapse=';'))][]

Оба дают следующий результат

              text v1 v2 v3 v4 v5       v6
1:     1;2;3;4;5;6  1  2  3  4  5  6;NA;NA
2: 1;2;3;4;5;6;7;8  1  2  3  4  5    6;7;8
3:       1;2;3;4;5  1  2  3  4  5 NA;NA;NA

NA производятся, чтобы сохранить длину элементов списка одинаковой. Но добавление [, v6 := gsub(";NA", "", v6)] дальше в цепочку удаляет NA

DT[, c("v1", "v2", "v3", "v4", "v5") := tstrsplit(text , ";")[1:5]
   ][, v6 := transpose(lapply(transpose(tstrsplit(text, ";")[-c(1:5)]), paste0, collapse=';'))
     ][, v6 := gsub(";NA", "", v6)][]

Наконец давая

              text v1 v2 v3 v4 v5    v6
1:     1;2;3;4;5;6  1  2  3  4  5     6
2: 1;2;3;4;5;6;7;8  1  2  3  4  5 6;7;8
3:       1;2;3;4;5  1  2  3  4  5    NA

Проблема в том, что в строке 201 есть 9 столбцов, но на данный момент fread решил, что есть максимум 8 столбцов. Вы можете взломать его, чтобы прочитать все 9 столбцов с помощью следующей команды:

x <- fread("test.txt",fill=TRUE, sep = "\t", colClasses=rep("logical",9))

Если 9 недостаточно, увеличивайте это число до тех пор, пока вы больше не увидите эту ошибку. На самом деле это не должно приводить какие-либо столбцы к логическим (при указании аргумента colClassesdata.table::fread отказывается приводить классы столбцов таким образом, что это приводит к потере информации). Я не уверен, какой штраф вызывает этот подход, но я думаю, что он быстрее, чем другие методы (по крайней мере, быстрее после того, как вы установили максимальное количество столбцов).

Если вы по-прежнему используете хочу для вставки столбцов 6+ вместе в один столбец, существует множество способов сделать это.

Для потомков см. ссылку, указанную в комментариях к вопросу (https://github.com/Rdatatable/data.table/issues/2727), чтобы узнать, решена ли проблема.

Это должно работать... Я пробовал, но все равно ошибки... Я также пытался "установить" colclasses на именованный вектор... тоже ошибки...

Wimpel 01.04.2019 08:48

Другой вариант:

DT[, paste0("v", 1:5) := tstrsplit(text, ";", keep = 1:5)]
DT[, v6 := stringi::stri_match(text, regex = "^(?:.*?;){5}(.*)$")[,2]][]

Другие вопросы по теме