Mam skrypt, który wczytuje dane z pliku CSV do a, data.table
a następnie dzieli tekst w jednej kolumnie na kilka nowych kolumn. Obecnie używam tych lapply
i strsplit
funkcji, aby to zrobić. Oto przykład:
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
W powyższym przykładzie kolumna PREFIX
jest podzielona na dwie nowe kolumny PX
i PY
znak „_”.
Mimo że działa to dobrze, zastanawiałem się, czy istnieje lepszy (bardziej wydajny) sposób na zrobienie tego za pomocą data.table
. Moje prawdziwe zestawy danych mają> = 10 mln + wierszy, więc czas / wydajność pamięci stają się naprawdę ważne.
AKTUALIZACJA:
Zgodnie z sugestią @ Franka stworzyłem większy przypadek testowy i użyłem sugerowanych poleceń, ale stringr::str_split_fixed
trwa to znacznie dłużej niż oryginalna metoda.
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
Tak więc str_split_fixed
metoda trwa około 20 razy dłużej.
źródło
stringr
pakietu, to jest polecenie:str_split_fixed(PREFIX,"_",2)
. Nie odpowiadam, ponieważ nie testowałem przyspieszenia ... Lub w jednym kroku:dt[,c("PX","PY"):=data.table(str_split_fixed(PREFIX,"_",2))]
Odpowiedzi:
Aktualizacja: Od wersji 1.9.6 (na CRAN od września 2015) możemy użyć tej funkcji,
tstrsplit()
aby uzyskać wyniki bezpośrednio (i znacznie wydajniej):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()
w zasadzie jest opakowaniem dlatranspose(strsplit())
, gdzietranspose()
funkcja, również niedawno zaimplementowana, transponuje listę. Proszę zobaczyć?tstrsplit()
i?transpose()
przykłady.Zobacz historię starych odpowiedzi.
źródło
fread
, ale aby to zrobić, Musiałem użyćtempfile
(co wydaje się być wąskim gardłem), ponieważ nie wygląda na to, żefread
ma odpowiedniktext
argumentu. Podczas testowania z tymi przykładowymi danymi jego wydajność jest między Twoimia_spl
aa_sub
podejściami.Dodaję odpowiedź dla kogoś, kto nie używa wersji
data.table
1.9.5, a także chce rozwiązania jednowierszowego .dt[, c('PX','PY') := do.call(Map, c(f = c, strsplit(PREFIX, '-'))) ]
źródło
Korzystanie z
splitstackshape
pakietu: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
źródło
Możemy spróbować:
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
źródło
W przypadku tidyr rozwiązaniem jest:
separate(df,col = "PREFIX",into = c("PX", "PY"), sep = "_")
źródło