data.table 열에서 텍스트 문자열 분할


87

CSV 파일의 데이터를 a로 읽은 data.table다음 한 열의 텍스트를 여러 새 열로 분할 하는 스크립트가 있습니다. 현재이 작업을 수행하기 위해 lapply및 strsplit함수를 사용 하고 있습니다. 예를 들면 다음과 같습니다.

library("data.table")
df = data.table(PREFIX = c("A_B","A_C","A_D","B_A","B_C","B_D"),
                VALUE  = 1:6)
dt = as.data.table(df)

# split PREFIX into new columns
dt$PX = as.character(lapply(strsplit(as.character(dt$PREFIX), split="_"), "[", 1))
dt$PY = as.character(lapply(strsplit(as.character(dt$PREFIX), split="_"), "[", 2))

dt 
#    PREFIX VALUE PX PY
# 1:    A_B     1  A  B
# 2:    A_C     2  A  C
# 3:    A_D     3  A  D
# 4:    B_A     4  B  A
# 5:    B_C     5  B  C
# 6:    B_D     6  B  D 

열 위의 예에서 PREFIX두 개의 새로운 열로 분할 PX하고 PY은 "_"캐릭터는.

이것이 잘 작동하지만을 사용하여 더 나은 (더 효율적인) 방법이 있는지 궁금합니다 data.table. 내 실제 데이터 세트에는 1000 만 이상의 행이 있으므로 시간 / 메모리 효율성이 정말 중요합니다.


최신 정보:

@Frank의 제안에 따라 더 큰 테스트 케이스를 만들고 제안 된 명령을 사용했지만 stringr::str_split_fixed원래 방법보다 훨씬 오래 걸립니다.

library("data.table")
library("stringr")
system.time ({
    df = data.table(PREFIX = rep(c("A_B","A_C","A_D","B_A","B_C","B_D"), 1000000),
                    VALUE  = rep(1:6, 1000000))
    dt = data.table(df)
})
#   user  system elapsed 
#  0.682   0.075   0.758 

system.time({ dt[, c("PX","PY") := data.table(str_split_fixed(PREFIX,"_",2))] })
#    user  system elapsed 
# 738.283   3.103 741.674 

rm(dt)
system.time ( {
    df = data.table(PREFIX = rep(c("A_B","A_C","A_D","B_A","B_C","B_D"), 1000000),
                     VALUE = rep(1:6, 1000000) )
    dt = as.data.table(df)
})
#    user  system elapsed 
#   0.123   0.000   0.123 

# split PREFIX into new columns
system.time ({
    dt$PX = as.character(lapply(strsplit(as.character(dt$PREFIX), split="_"), "[", 1))
    dt$PY = as.character(lapply(strsplit(as.character(dt$PREFIX), split="_"), "[", 2))
})
#    user  system elapsed 
#  33.185   0.000  33.191 

따라서이 str_split_fixed방법은 약 20 배 더 오래 걸립니다.


data.table 외부에서 먼저 작업을 수행하는 것이 더 좋을 것이라고 생각합니다. stringr패키지 를 사용하는 경우 다음 명령이 str_split_fixed(PREFIX,"_",2)있습니다.. 속도 향상을 테스트하지 않았기 때문에 응답하지 않습니다. 또는 한 단계로 :dt[,c("PX","PY"):=data.table(str_split_fixed(PREFIX,"_",2))]
— Frank

답변:


123

업데이트 : 버전 1.9.6 (CRAN에서 9 월 15 일 기준)부터이 함수 tstrsplit()를 사용 하여 결과를 직접 (그리고 훨씬 더 효율적인 방식으로) 얻을 수 있습니다.

require(data.table) ## v1.9.6+
dt[, c("PX", "PY") := tstrsplit(PREFIX, "_", fixed=TRUE)]
#    PREFIX VALUE PX PY
# 1:    A_B     1  A  B
# 2:    A_C     2  A  C
# 3:    A_D     3  A  D
# 4:    B_A     4  B  A
# 5:    B_C     5  B  C
# 6:    B_D     6  B  D

tstrsplit()기본적으로에 대한 래퍼입니다 transpose(strsplit()). 여기서 transpose()함수도 최근에 구현되어 목록을 전치합니다. ?tstrsplit()및 ?transpose()예를 참조하십시오 .

이전 답변에 대한 기록을 참조하십시오.


고마워 Arun. "a_spl"에 설명 된대로 먼저 목록을 만든 다음 인덱스와 열을 만드는 방법을 생각하지 못했습니다. 저는 항상 모든 것을 한 줄로하는 것이 가장 좋은 방법이라고 생각했습니다. 호기심 때문에 인덱스 방식이 왜 그렇게 빨리 작동합니까?
— Derric Lewis 2013 년

@Arun,이 질문과 관련하여 여기에 작성한 것과 같은 함수에서 볼 수있는 함정은 무엇입니까? gist.github.com/mrdwab/6873058 기본적으로를 사용 fread했지만 그렇게하기 위해 나는 인수 와 동등한 tempfile것 같지 않기 때문에 (병목처럼 보일 것 같은) a를 사용해야했습니다 . 이 샘플 데이터로 테스트하면 성능이 사용자 와 접근 방식 사이에 있습니다 . freadtexta_spla_sub
— A5C1D2H2I1M1N2O1R2T1 2014-06-02

4
나는 LHS에서 : =의 열 수를 추측 하고 grep tstrsplit 발생을 기반으로 새 열의 이름을 동적으로 생성하는 방법을 궁금해했습니다
— amonk

이 방법을 사용하여 원본 PREFIX 열을 한 번에 모두 삭제하는 효율적인 방법이 있습니까? 즉, 연결하거나 별도의 작업으로 수행하는 것보다 프로세스에서 더 빠르거나 더 적은 메모리를 사용할 수 있습니다.
— Mark E.

15

data.table v1.9.5를 사용하지 않고 한 줄 솔루션을 원하는 사람에게 답변을 추가 합니다.

dt[, c('PX','PY') := do.call(Map, c(f = c, strsplit(PREFIX, '-'))) ]

7

splitstackshape패키지 사용 :

library(splitstackshape)
cSplit(df, splitCols = "PREFIX", sep = "_", direction = "wide", drop = FALSE)
#    PREFIX VALUE PREFIX_1 PREFIX_2
# 1:    A_B     1        A        B
# 2:    A_C     2        A        C
# 3:    A_D     3        A        D
# 4:    B_A     4        B        A
# 5:    B_C     5        B        C
# 6:    B_D     6        B        D

4

시도해 볼 수 있습니다.

library(data.table)  
cbind(dt, fread(text = dt$PREFIX, sep = "_", header = FALSE))
    #    PREFIX VALUE V1 V2
    # 1:    A_B     1  A  B
    # 2:    A_C     2  A  C
    # 3:    A_D     3  A  D
    # 4:    B_A     4  B  A
    # 5:    B_C     5  B  C
    # 6:    B_D     6  B  D

1

깔끔한 솔루션은 다음과 같습니다.

separate(df,col = "PREFIX",into = c("PX", "PY"), sep = "_")

이 질문은 특별히 data.table 솔루션을 요구했습니다. 이 분야에서 일하는 사람들은 자신의 과제와 관련된 좋은 이유로 이미 깔끔한 솔루션보다 data.table 솔루션을 선택했습니다.
— Michael Tuchman

다른 사용자들도 다른 라이브러리와 함께 솔루션을 제공했으며, 방금 유효한 대안을 쉽고 빠르게 제공했습니다.
— skan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.