Ich habe ein Skript, das Daten aus einer CSV-Datei in eine einliest data.table
und dann den Text in einer Spalte in mehrere neue Spalten aufteilt. Ich benutze derzeit die lapply
und strsplit
Funktionen, um dies zu tun. Hier ist ein Beispiel:
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
Im obigen Beispiel wird die Spalte PREFIX
in zwei neue Spalten PX
und PY
mit dem Zeichen "_" aufgeteilt.
Obwohl dies gut funktioniert, habe ich mich gefragt, ob es einen besseren (effizienteren) Weg gibt, dies mit zu tun data.table
. Meine realen Datensätze haben> = 10M + Zeilen, daher wird die Zeit- / Speichereffizienz wirklich wichtig.
AKTUALISIEREN:
Auf @ Franks Vorschlag hin habe ich einen größeren Testfall erstellt und die vorgeschlagenen Befehle verwendet, aber das stringr::str_split_fixed
dauert viel länger als die ursprüngliche Methode.
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
Die str_split_fixed
Methode dauert also etwa 20-mal länger.
quelle
stringr
Paket verwenden, ist dies der Befehl :str_split_fixed(PREFIX,"_",2)
. Ich antworte nicht, weil ich die Beschleunigung nicht getestet habe ... Oder in einem Schritt:dt[,c("PX","PY"):=data.table(str_split_fixed(PREFIX,"_",2))]
Antworten:
Update: Ab Version 1.9.6 (auf CRAN ab 15. September) können wir die Funktion verwenden
tstrsplit()
, um die Ergebnisse direkt (und auf viel effizientere Weise) abzurufen :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()
Im Grunde ist es ein Wrapper fürtranspose(strsplit())
, bei dem dietranspose()
ebenfalls kürzlich implementierte Funktion eine Liste transponiert. Bitte sehen Sie?tstrsplit()
und?transpose()
für Beispiele.In der Geschichte finden Sie alte Antworten.
quelle
fread
, aber um dies zu tun, Ich musste ein verwendentempfile
(was wie ein Engpass erscheinen würde), da es nicht so aussieht, als hättefread
es ein Äquivalent zu einemtext
Argument. Beim Testen mit diesen Beispieldaten liegt die Leistung zwischen Ihrena_spl
und Ihrena_sub
Ansätzen.Ich füge eine Antwort für jemanden hinzu, der
data.table
v1.9.5 nicht verwendet und auch eine einzeilige Lösung möchte.dt[, c('PX','PY') := do.call(Map, c(f = c, strsplit(PREFIX, '-'))) ]
quelle
Mit
splitstackshape
Paket: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
quelle
Wir könnten es versuchen:
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
quelle
Mit tidyr lautet die Lösung:
separate(df,col = "PREFIX",into = c("PX", "PY"), sep = "_")
quelle