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


87

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

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.