열에서 쉼표로 구분된 문자열을 별도의 행으로 분할
다음과 같은 데이터 프레임이 있습니다.
data.frame(director = c("Aaron Blaise,Bob Walker", "Akira Kurosawa",
"Alan J. Pakula", "Alan Parker", "Alejandro Amenabar", "Alejandro Gonzalez Inarritu",
"Alejandro Gonzalez Inarritu,Benicio Del Toro", "Alejandro González Iñárritu",
"Alex Proyas", "Alexander Hall", "Alfonso Cuaron", "Alfred Hitchcock",
"Anatole Litvak", "Andrew Adamson,Marilyn Fox", "Andrew Dominik",
"Andrew Stanton", "Andrew Stanton,Lee Unkrich", "Angelina Jolie,John Stevenson",
"Anne Fontaine", "Anthony Harvey"), AB = c('A', 'B', 'A', 'A', 'B', 'B', 'B', 'A', 'B', 'A', 'B', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B', 'A'))
보다시피, 의 일부 항목은director
열은 쉼표로 구분된 여러 이름입니다.다른 열의 값을 유지하면서 이 항목을 별도의 행으로 나누고 싶습니다.예를 들어, 위의 데이터 프레임의 첫 번째 행은 두 행으로 분할되어야 하며, 각각의 행은 하나의 이름을 가지고 있어야 합니다.director
열 및 'A'의AB
기둥.
몇 가지 대안:
data.table을 사용하는 두 가지 방법:
library(data.table)
# method 1 (preferred)
setDT(v)[, lapply(.SD, function(x) unlist(tstrsplit(x, ",", fixed=TRUE))), by = AB
][!is.na(director)]
# method 2
setDT(v)[, strsplit(as.character(director), ",", fixed=TRUE), by = .(AB, director)
][,.(director = V1, AB)]
library(dplyr)
library(tidyr)
v %>%
mutate(director = strsplit(as.character(director), ",")) %>%
unnest(director)
조수만 있는 경우:(및 이후 버전)을 사용할 수도 있습니다.separate_rows
:
separate_rows(v, director, sep = ",")
사용할 수 있습니다.convert = TRUE
숫자를 숫자 열로 자동 변환하는 매개 변수입니다.
(나중에) 사용할 수 있습니다.separate_longer_delim
(및separate_rows
이제 대체됨):
separate_longer_delim(v, director, delim = ",")
기준 R:
# if 'director' is a character-column:
stack(setNames(strsplit(df$director,','), df$AB))
# if 'director' is a factor-column:
stack(setNames(strsplit(as.character(df$director),','), df$AB))
이 오래된 질문은 종종 이중 대상으로 사용됩니다(태그 부착).r-faq
). 현재까지 6가지 접근 방식을 제시하며 세 번 답변을 받았지만 어떤 접근 방식이 가장1 빠른지에 대한 지침으로 벤치마크가 부족합니다.
벤치마크된 솔루션은 다음과 같습니다.
- Matthew Lundberg의 기본 R 접근법이지만 Rich Scriven의 의견에 따라 수정되었습니다.
- 야프의 두 개
data.table
방법과 두 가지dplyr
/tidyr
접근, - 아난다의 해결책,
- 그리고 일본의 두 가지 추가 변형.
data.table
방법들.
전체적으로 8가지 다른 방법이 6가지 크기의 데이터 프레임에서 벤치마크되었습니다.microbenchmark
패키지(아래 코드 참조).
OP가 제공한 표본 데이터는 20개의 행으로만 구성됩니다.더 큰 데이터 프레임을 생성하기 위해 이 20개의 행을 1, 10, 100, 1000, 10000 및 100000회 반복하기만 하면 최대 200만 행의 문제 크기를 얻을 수 있습니다.
벤치마크 결과
벤치마크 결과에 따르면 충분히 큰 데이터 프레임의 경우data.table
메소드는 다른 메소드보다 빠릅니다.약 5,000개 이상의 행이 있는 데이터 프레임의 경우 Jap의data.table
방법 2와 변형DT3
가장 빠르고, 가장 느린 방법보다 크기가 더 빠릅니다.
놀랍게도, 두 사람의 시간은tidyverse
방법 및splistackshape
솔루션이 너무 유사하여 차트의 곡선을 구별하기가 어렵습니다.모든 데이터 프레임 크기에서 벤치마크된 방법 중 가장 느립니다.
데이터 프레임의 R 과 Matt의 기본 R 솔루션을 사용합니다.data.table
메소드 4는 다른 메소드보다 오버헤드가 적은 것으로 보입니다.
코드
director <-
c("Aaron Blaise,Bob Walker", "Akira Kurosawa", "Alan J. Pakula",
"Alan Parker", "Alejandro Amenabar", "Alejandro Gonzalez Inarritu",
"Alejandro Gonzalez Inarritu,Benicio Del Toro", "Alejandro González Iñárritu",
"Alex Proyas", "Alexander Hall", "Alfonso Cuaron", "Alfred Hitchcock",
"Anatole Litvak", "Andrew Adamson,Marilyn Fox", "Andrew Dominik",
"Andrew Stanton", "Andrew Stanton,Lee Unkrich", "Angelina Jolie,John Stevenson",
"Anne Fontaine", "Anthony Harvey")
AB <- c("A", "B", "A", "A", "B", "B", "B", "A", "B", "A", "B", "A",
"A", "B", "B", "B", "B", "B", "B", "A")
library(data.table)
library(magrittr)
문 제 크 크 대 함 수 한 정 의n
run_mb <- function(n) {
# compute number of benchmark runs depending on problem size `n`
mb_times <- scales::squish(10000L / n , c(3L, 100L))
cat(n, " ", mb_times, "\n")
# create data
DF <- data.frame(director = rep(director, n), AB = rep(AB, n))
DT <- as.data.table(DF)
# start benchmarks
microbenchmark::microbenchmark(
matt_mod = {
s <- strsplit(as.character(DF$director), ',')
data.frame(director=unlist(s), AB=rep(DF$AB, lengths(s)))},
jaap_DT1 = {
DT[, lapply(.SD, function(x) unlist(tstrsplit(x, ",", fixed=TRUE))), by = AB
][!is.na(director)]},
jaap_DT2 = {
DT[, strsplit(as.character(director), ",", fixed=TRUE),
by = .(AB, director)][,.(director = V1, AB)]},
jaap_dplyr = {
DF %>%
dplyr::mutate(director = strsplit(as.character(director), ",")) %>%
tidyr::unnest(director)},
jaap_tidyr = {
tidyr::separate_rows(DF, director, sep = ",")},
cSplit = {
splitstackshape::cSplit(DF, "director", ",", direction = "long")},
DT3 = {
DT[, strsplit(as.character(director), ",", fixed=TRUE),
by = .(AB, director)][, director := NULL][
, setnames(.SD, "V1", "director")]},
DT4 = {
DT[, .(director = unlist(strsplit(as.character(director), ",", fixed = TRUE))),
by = .(AB)]},
times = mb_times
)
}
다양한 문제 크기에 대한 벤치마크 실행
# define vector of problem sizes
n_rep <- 10L^(0:5)
# run benchmark for different problem sizes
mb <- lapply(n_rep, run_mb)
플롯을 위한 데이터 준비
mbl <- rbindlist(mb, idcol = "N")
mbl[, n_row := NROW(director) * n_rep[N]]
mba <- mbl[, .(median_time = median(time), N = .N), by = .(n_row, expr)]
mba[, expr := forcats::fct_reorder(expr, -median_time)]
차트 생성
library(ggplot2)
ggplot(mba, aes(n_row, median_time*1e-6, group = expr, colour = expr)) +
geom_point() + geom_smooth(se = FALSE) +
scale_x_log10(breaks = NROW(director) * n_rep) + scale_y_log10() +
xlab("number of rows") + ylab("median of execution time [ms]") +
ggtitle("microbenchmark results") + theme_bw()
세션 정보 및 패키지 버전(예외)
devtools::session_info()
#Session info
# version R version 3.3.2 (2016-10-31)
# system x86_64, mingw32
#Packages
# data.table * 1.10.4 2017-02-01 CRAN (R 3.3.2)
# dplyr 0.5.0 2016-06-24 CRAN (R 3.3.1)
# forcats 0.2.0 2017-01-23 CRAN (R 3.3.2)
# ggplot2 * 2.2.1 2016-12-30 CRAN (R 3.3.2)
# magrittr * 1.5 2014-11-22 CRAN (R 3.3.0)
# microbenchmark 1.4-2.1 2015-11-25 CRAN (R 3.3.3)
# scales 0.4.1 2016-11-09 CRAN (R 3.3.2)
# splitstackshape 1.4.2 2014-10-23 CRAN (R 3.3.3)
# tidyr 0.6.1 2017-01-10 CRAN (R 3.3.2)
1 나의 호기심은 이 활기찬 댓글에 자극받았습니다 Brilliant! 더 빠른 속도로!tidyverse
이 질문의 중복으로 종결된 질문의 답변.
data.에 data.frame 이름 v
다음과 같은 것이 있습니다.
> s <- strsplit(as.character(v$director), ',')
> data.frame(director=unlist(s), AB=rep(v$AB, sapply(s, FUN=length)))
director AB
1 Aaron Blaise A
2 Bob Walker A
3 Akira Kurosawa B
4 Alan J. Pakula A
5 Alan Parker A
6 Alejandro Amenabar B
7 Alejandro Gonzalez Inarritu B
8 Alejandro Gonzalez Inarritu B
9 Benicio Del Toro B
10 Alejandro González Iñárritu A
11 Alex Proyas B
12 Alexander Hall A
13 Alfonso Cuaron B
14 Alfred Hitchcock A
15 Anatole Litvak A
16 Andrew Adamson B
17 Marilyn Fox B
18 Andrew Dominik B
19 Andrew Stanton B
20 Andrew Stanton B
21 Lee Unkrich B
22 Angelina Jolie B
23 John Stevenson B
24 Anne Fontaine B
25 Anthony Harvey A
의 사용에 주의합니다.rep
새 AB 열을 작성합니다.여기서,sapply
각 원래 행의 이름 수를 반환합니다.
파티에 늦었지만, 또 다른 일반적인 대안은cSplit
내 "스택 모양" 패키지에서 다음을 포함합니다.direction
논쟁.다음으로 설정"long"
지정한 결과를 얻는 방법:
library(splitstackshape)
head(cSplit(mydf, "director", ",", direction = "long"))
# director AB
# 1: Aaron Blaise A
# 2: Bob Walker A
# 3: Akira Kurosawa B
# 4: Alan J. Pakula A
# 5: Alan Parker A
# 6: Alejandro Amenabar B
devtools::install_github("yikeshu0611/onetree")
library(onetree)
dd=spread_byonecolumn(data=mydata,bycolumn="director",joint=",")
head(dd)
director AB
1 Aaron Blaise A
2 Bob Walker A
3 Akira Kurosawa B
4 Alan J. Pakula A
5 Alan Parker A
6 Alejandro Amenabar B
사용한 또 strsplit
from base는 현재 열에서 쉼표로 구분된 문자열을 다른 행으로 분할하는 것이 좋습니다. 이는 광범위한 크기에서 가장 빠르기 때문입니다.
s <- strsplit(v$director, ",", fixed=TRUE)
s <- data.frame(director=unlist(s), AB=rep(v$AB, lengths(s)))
로 참: 사를 사용합니다.fixed=TRUE
시간에 상당한 영향을 미칩니다.
비교 방법:
met <- alist(base = {s <- strsplit(v$director, ",") #Matthew Lundberg
s <- data.frame(director=unlist(s), AB=rep(v$AB, sapply(s, FUN=length)))}
, baseLength = {s <- strsplit(v$director, ",") #Rich Scriven
s <- data.frame(director=unlist(s), AB=rep(v$AB, lengths(s)))}
, baseLeFix = {s <- strsplit(v$director, ",", fixed=TRUE)
s <- data.frame(director=unlist(s), AB=rep(v$AB, lengths(s)))}
, cSplit = s <- cSplit(v, "director", ",", direction = "long") #A5C1D2H2I1M1N2O1R2T1
, dt = s <- setDT(v)[, lapply(.SD, function(x) unlist(tstrsplit(x, "," #Jaap
, fixed=TRUE))), by = AB][!is.na(director)]
#, dt2 = s <- setDT(v)[, strsplit(director, "," #Jaap #Only Unique
# , fixed=TRUE), by = .(AB, director)][,.(director = V1, AB)]
, dplyr = {s <- v %>% #Jaap
mutate(director = strsplit(director, ",", fixed=TRUE)) %>%
unnest(director)}
, tidyr = s <- separate_rows(v, director, sep = ",") #Jaap
, stack = s <- stack(setNames(strsplit(v$director, ",", fixed=TRUE), v$AB)) #Jaap
#, dt3 = {s <- setDT(v)[, strsplit(director, ",", fixed=TRUE), #Uwe #Only Unique
# by = .(AB, director)][, director := NULL][, setnames(.SD, "V1", "director")]}
, dt4 = {s <- setDT(v)[, .(director = unlist(strsplit(director, "," #Uwe
, fixed = TRUE))), by = .(AB)]}
, dt5 = {s <- vT[, .(director = unlist(strsplit(director, "," #Uwe
, fixed = TRUE))), by = .(AB)]}
)
라이브러리:
library(microbenchmark)
library(splitstackshape) #cSplit
library(data.table) #dt, dt2, dt3, dt4
#setDTthreads(1) #Looks like it has here minor effect
library(dplyr) #dplyr
library(tidyr) #dplyr, tidyr
데이터:
v0 <- data.frame(director = c("Aaron Blaise,Bob Walker", "Akira Kurosawa",
"Alan J. Pakula", "Alan Parker", "Alejandro Amenabar", "Alejandro Gonzalez Inarritu",
"Alejandro Gonzalez Inarritu,Benicio Del Toro", "Alejandro González Iñárritu",
"Alex Proyas", "Alexander Hall", "Alfonso Cuaron", "Alfred Hitchcock",
"Anatole Litvak", "Andrew Adamson,Marilyn Fox", "Andrew Dominik",
"Andrew Stanton", "Andrew Stanton,Lee Unkrich", "Angelina Jolie,John Stevenson",
"Anne Fontaine", "Anthony Harvey"), AB = c('A', 'B', 'A', 'A', 'B', 'B', 'B', 'A', 'B', 'A', 'B', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B', 'A'))
계산 및 타이밍 결과:
n <- 10^(0:5)
x <- lapply(n, function(n) {v <- v0[rep(seq_len(nrow(v0)), n),]
vT <- setDT(v)
ti <- min(100, max(3, 1e4/n))
microbenchmark(list = met, times = ti, control=list(order="block"))})
y <- do.call(cbind, lapply(x, function(y) aggregate(time ~ expr, y, median)))
y <- cbind(y[1], y[-1][c(TRUE, FALSE)])
y[-1] <- y[-1] / 1e6 #ms
names(y)[-1] <- paste("n:", n * nrow(v0))
y #Time in ms
# expr n: 20 n: 200 n: 2000 n: 20000 n: 2e+05 n: 2e+06
#1 base 0.2989945 0.6002820 4.8751170 46.270246 455.89578 4508.1646
#2 baseLength 0.2754675 0.5278900 3.8066300 37.131410 442.96475 3066.8275
#3 baseLeFix 0.2160340 0.2424550 0.6674545 4.745179 52.11997 555.8610
#4 cSplit 1.7350820 2.5329525 11.6978975 99.060448 1053.53698 11338.9942
#5 dt 0.7777790 0.8420540 1.6112620 8.724586 114.22840 1037.9405
#6 dplyr 6.2425970 7.9942780 35.1920280 334.924354 4589.99796 38187.5967
#7 tidyr 4.0323765 4.5933730 14.7568235 119.790239 1294.26959 11764.1592
#8 stack 0.2931135 0.4672095 2.2264155 22.426373 289.44488 2145.8174
#9 dt4 0.5822910 0.6414900 1.2214470 6.816942 70.20041 787.9639
#10 dt5 0.5015235 0.5621240 1.1329110 6.625901 82.80803 636.1899
참고, 다음과 같은 방법
(v <- rbind(v0[1:2,], v0[1,]))
# director AB
#1 Aaron Blaise,Bob Walker A
#2 Akira Kurosawa B
#3 Aaron Blaise,Bob Walker A
setDT(v)[, strsplit(director, "," #Jaap #Only Unique
, fixed=TRUE), by = .(AB, director)][,.(director = V1, AB)]
# director AB
#1: Aaron Blaise A
#2: Bob Walker A
#3: Akira Kurosawa B
례로를 strsplit
위해서unique
감독과 비견될 수도 있습니다.
tmp <- unique(v)
s <- strsplit(tmp$director, ",", fixed=TRUE)
s <- data.frame(director=unlist(s), AB=rep(tmp$AB, lengths(s)))
하지만 제가 이해하기로는, 이것은 요청되지 않았습니다.
언급URL : https://stackoverflow.com/questions/13773770/split-comma-separated-strings-in-a-column-into-separate-rows
'programing' 카테고리의 다른 글
mocha test vue 템플릿이지만 babel이 'computed:{...mapGetters()}'을(를) 분석할 수 없습니다. (0) | 2023.06.17 |
---|---|
여러 장치가 연결되어 있을 때 ADB Shell을 사용하는 방법은 무엇입니까?"오류: 둘 이상의 장치 및 에뮬레이터"로 실패함 (0) | 2023.06.17 |
IntegrinentAttributes & IntegrinentClassAttributesReact.js 유형에는 할당할 수 없습니다. (0) | 2023.06.17 |
Python 요청 및 영구 세션 (0) | 2023.06.17 |
나중에 사용할 수 있도록 TypeScript 개체 구조 정의 (0) | 2023.06.17 |