여러 열을 함께 붙여넣기
데이터 프레임에 다음과 같이 "-"로 구분하여 붙여넣을 열이 여러 개 있습니다.
data <- data.frame('a' = 1:3,
'b' = c('a','b','c'),
'c' = c('d', 'e', 'f'),
'd' = c('g', 'h', 'i'))
i.e.
a b c d
1 a d g
2 b e h
3 c f i
내가 되고 싶은 것:
a x
1 a-d-g
2 b-e-h
3 c-f-i
일반적으로 다음 작업을 수행할 수 있습니다.
within(data, x <- paste(b,c,d,sep='-'))
그리고 나서 오래된 열을 제거하지만, 안타깝게도 저는 열의 이름을 구체적으로 알지 못합니다. 모든 열의 집합적인 이름만 알고 있습니다. 예를 들어, 저는 그것을 알고 있습니다.cols <- c('b','c','d')
이것을 하는 방법을 아는 사람이 있습니까?
# your starting data..
data <- data.frame('a' = 1:3, 'b' = c('a','b','c'), 'c' = c('d', 'e', 'f'), 'd' = c('g', 'h', 'i'))
# columns to paste together
cols <- c( 'b' , 'c' , 'd' )
# create a new column `x` with the three columns collapsed together
data$x <- apply( data[ , cols ] , 1 , paste , collapse = "-" )
# remove the unnecessary columns
data <- data[ , !( names( data ) %in% cols ) ]
침례교 신자의 대답에 대한 변형으로서,data
사용자 정의 및 함께 사용할 열 정의cols
cols <- c("b", "c", "d")
다음에 새 열을 추가할 수 있습니다.data
그리고 오래된 것들을 삭제합니다.
data$x <- do.call(paste, c(data[cols], sep="-"))
for (co in cols) data[co] <- NULL
이는
> data
a x
1 1 a-d-g
2 2 b-e-h
3 3 c-f-i
사용.tidyr
패키지, 이것은 한 번의 함수 호출로 쉽게 처리할 수 있습니다.
data <- data.frame('a' = 1:3,
'b' = c('a','b','c'),
'c' = c('d', 'e', 'f'),
'd' = c('g', 'h', 'i'))
tidyr::unite_(data, paste(colnames(data)[-1], collapse="_"), colnames(data)[-1])
a b_c_d
1 1 a_d_g
2 2 b_e_h
3 3 c_f_i
편집: 첫 번째 열은 제외하고 다른 모든 열은 붙여넣습니다.
# tidyr_0.6.3
unite(data, newCol, -a)
# or by column index unite(data, newCol, -1)
# a newCol
# 1 1 a_d_g
# 2 2 b_e_h
# 3 3 c_f_i
새 data.frame을 구성합니다.
d <- data.frame('a' = 1:3, 'b' = c('a','b','c'), 'c' = c('d', 'e', 'f'), 'd' = c('g', 'h', 'i'))
cols <- c( 'b' , 'c' , 'd' )
data.frame(a = d[, 'a'], x = do.call(paste, c(d[ , cols], list(sep = '-'))))
솔루션을 추가하는 것만으로도Reduce
그것은 아마도 더 느릴 것입니다.do.call
하지만 조사하는 것이 더 낫습니다.apply
왜냐하면 그것은 피할 것이기 때문입니다.matrix
전환또한, 대신에for
우리가 그냥 사용할 수 있는 루프.setdiff
원하지 않는 열을 제거하기 위해
cols <- c('b','c','d')
data$x <- Reduce(function(...) paste(..., sep = "-"), data[cols])
data[setdiff(names(data), cols)]
# a x
# 1 1 a-d-g
# 2 2 b-e-h
# 3 3 c-f-i
또는 업데이트할 수 있습니다.data
를 사용하여 제자리에data.table
패키지(신규 데이터 포함)
library(data.table)
setDT(data)[, x := Reduce(function(...) paste(..., sep = "-"), .SD[, mget(cols)])]
data[, (cols) := NULL]
data
# a x
# 1: 1 a-d-g
# 2: 2 b-e-h
# 3: 3 c-f-i
다른 옵션은 다음과 같습니다..SDcols
대신에mget
에 있어서와 같이
setDT(data)[, x := Reduce(function(...) paste(..., sep = "-"), .SD), .SDcols = cols]
내 생각에는.sprintf
-기능 또한 이 답변들 중 한 자리를 차지할 가치가 있습니다.사용할 수 있습니다.sprintf
다음과 같이:
do.call(sprintf, c(d[cols], '%s-%s-%s'))
이는 다음을 제공합니다.
[1] "a-d-g" "b-e-h" "c-f-i"
필요한 데이터 프레임을 생성하려면 다음과 같이 하십시오.
data.frame(a = d$a, x = do.call(sprintf, c(d[cols], '%s-%s-%s')))
제공:
a x
1 1 a-d-g
2 2 b-e-h
3 3 c-f-i
비록 ~일지라도sprintf
그것보다 확실한 우위를 가지고 있지 않습니다.do.call
/paste
@BrianDiggs의 조합으로, 원하는 문자열의 특정 부분을 채우기를 원하거나 자릿수를 지정할 때 특히 유용합니다.봐?sprintf
몇 가지 옵션에 대해.
또 다른 변형은 다음과 같습니다.pmap
purrr에서:
pmap(d[2:4], paste, sep = '-')
참고: 이 항목pmap
열이 요인이 아닌 경우에만 솔루션이 작동합니다.
대규모 데이터셋에 대한 벤치마크:
# create a larger dataset
d2 <- d[sample(1:3,1e6,TRUE),]
# benchmark
library(microbenchmark)
microbenchmark(
docp = do.call(paste, c(d2[cols], sep="-")),
appl = apply( d2[, cols ] , 1 , paste , collapse = "-" ),
tidr = tidyr::unite_(d2, "x", cols, sep="-")$x,
docs = do.call(sprintf, c(d2[cols], '%s-%s-%s')),
times=10)
결과:
Unit: milliseconds
expr min lq mean median uq max neval cld
docp 214.1786 226.2835 297.1487 241.6150 409.2495 493.5036 10 a
appl 3832.3252 4048.9320 4131.6906 4072.4235 4255.1347 4486.9787 10 c
tidr 206.9326 216.8619 275.4556 252.1381 318.4249 407.9816 10 a
docs 413.9073 443.1550 490.6520 453.1635 530.1318 659.8400 10 b
사용된 데이터:
d <- data.frame(a = 1:3, b = c('a','b','c'), c = c('d','e','f'), d = c('g','h','i'))
Anthony Damico, Brian Diggs 및 data_steve의 답변을 작은 샘플로 벤치마킹했습니다.tbl_df
그리고 다음과 같은 결과를 얻었습니다.
> data <- data.frame('a' = 1:3,
+ 'b' = c('a','b','c'),
+ 'c' = c('d', 'e', 'f'),
+ 'd' = c('g', 'h', 'i'))
> data <- tbl_df(data)
> cols <- c("b", "c", "d")
> microbenchmark(
+ do.call(paste, c(data[cols], sep="-")),
+ apply( data[ , cols ] , 1 , paste , collapse = "-" ),
+ tidyr::unite_(data, "x", cols, sep="-")$x,
+ times=1000
+ )
Unit: microseconds
expr min lq mean median uq max neval
do.call(paste, c(data[cols], sep = "-")) 65.248 78.380 93.90888 86.177 99.3090 436.220 1000
apply(data[, cols], 1, paste, collapse = "-") 223.239 263.044 313.11977 289.514 338.5520 743.583 1000
tidyr::unite_(data, "x", cols, sep = "-")$x 376.716 448.120 556.65424 501.877 606.9315 11537.846 1000
하지만, 제가 스스로 평가했을 때.tbl_df
100만 개의 행과 10개의 열이 있는 경우 결과는 상당히 다릅니다.
> microbenchmark(
+ do.call(paste, c(data[c("a", "b")], sep="-")),
+ apply( data[ , c("a", "b") ] , 1 , paste , collapse = "-" ),
+ tidyr::unite_(data, "c", c("a", "b"), sep="-")$c,
+ times=25
+ )
Unit: milliseconds
expr min lq mean median uq max neval
do.call(paste, c(data[c("a", "b")], sep="-")) 930.7208 951.3048 1129.334 997.2744 1066.084 2169.147 25
apply( data[ , c("a", "b") ] , 1 , paste , collapse = "-" ) 9368.2800 10948.0124 11678.393 11136.3756 11878.308 17587.617 25
tidyr::unite_(data, "c", c("a", "b"), sep="-")$c 968.5861 1008.4716 1095.886 1035.8348 1082.726 1759.349 25
다음은 상당히 파격적인(그러나 빠른) 접근 방식입니다.fwrite
부터data.table
열을 함께 "재결합"하고,fread
다시 읽어보기 위해서야편의를 위해 단계를 다음과 같은 기능으로 작성했습니다.fpaste
:
fpaste <- function(dt, sep = ",") {
x <- tempfile()
fwrite(dt, file = x, sep = sep, col.names = FALSE)
fread(x, sep = "\n", header = FALSE)
}
다음은 예입니다.
d <- data.frame(a = 1:3, b = c('a','b','c'), c = c('d','e','f'), d = c('g','h','i'))
cols = c("b", "c", "d")
fpaste(d[cols], "-")
# V1
# 1: a-d-g
# 2: b-e-h
# 3: c-f-i
성능이 어떻습니까?
d2 <- d[sample(1:3,1e6,TRUE),]
library(microbenchmark)
microbenchmark(
docp = do.call(paste, c(d2[cols], sep="-")),
tidr = tidyr::unite_(d2, "x", cols, sep="-")$x,
docs = do.call(sprintf, c(d2[cols], '%s-%s-%s')),
appl = apply( d2[, cols ] , 1 , paste , collapse = "-" ),
fpaste = fpaste(d2[cols], "-")$V1,
dt2 = as.data.table(d2)[, x := Reduce(function(...) paste(..., sep = "-"), .SD), .SDcols = cols][],
times=10)
# Unit: milliseconds
# expr min lq mean median uq max neval
# docp 215.34536 217.22102 220.3603 221.44104 223.27224 225.0906 10
# tidr 215.19907 215.81210 220.7131 220.09636 225.32717 229.6822 10
# docs 281.16679 285.49786 289.4514 286.68738 290.17249 312.5484 10
# appl 2816.61899 3106.19944 3259.3924 3266.45186 3401.80291 3804.7263 10
# fpaste 88.57108 89.67795 101.1524 90.59217 91.76415 197.1555 10
# dt2 301.95508 310.79082 384.8247 316.29807 383.94993 874.4472 10
으로 간단하고 간단한 :unite
{tidyr} v1.2.0
있는 {tidyr v1.2.0}
library(tidyr)
data %>% unite("x", all_of(cols), remove = T, sep = "-")
"x"
새 열의 이름입니다.all_of(cols)
병합할 열을 선택한 것입니다.용사를 합니다.<tidy-select>
열 이름을 하드 코딩할 필요가 없습니다.remove = T
합니다.sep = "-"
이 의 구 자 값 정 니 다 합 의 사이의 합니다.- 다면이 있는
NA
우리는 또한 추가할 수 있습니다.na.rm = TRUE
산출량
# a x
# 1 1 a-d-g
# 2 2 b-e-h
# 3 3 c-f-i
입력 데이터
data <- data.frame('a' = 1:3,
'b' = c('a','b','c'),
'c' = c('d', 'e', 'f'),
'd' = c('g', 'h', 'i'))
cols <- c('b','c','d')
data
# a b c d
# 1 1 a d g
# 2 2 b e h
# 3 3 c f i
*이 솔루션은 이미 게시된 내용과 다릅니다.
오래된 질문인 것은 알지만 질문자가 제안한 것처럼 페이스트() 기능을 사용하여 간단한 해결책을 제시해야 한다고 생각했습니다.
data_1<-data.frame(a=data$a,"x"=paste(data$b,data$c,data$d,sep="-"))
data_1
a x
1 1 a-d-g
2 2 b-e-h
3 3 c-f-i
library(plyr)
ldply(apply(data, 1, function(x) data.frame(
x = paste(x[2:4],sep="",collapse="-"))))
# x
#1 a-d-g
#2 b-e-h
#3 c-f-i
# and with just the vector of names you have:
ldply(apply(data, 1, function(x) data.frame(
x = paste(x[c('b','c','d')],sep="",collapse="-"))))
# or equally:
mynames <-c('b','c','d')
ldply(apply(data, 1, function(x) data.frame(
x = paste(x[mynames],sep="",collapse="-"))))
언급URL : https://stackoverflow.com/questions/14568662/paste-multiple-columns-together
'programing' 카테고리의 다른 글
Ruby에서 파일을 만드는 방법 (0) | 2023.06.18 |
---|---|
파이썬에서 모니터 해상도를 얻으려면 어떻게 해야 합니까? (0) | 2023.06.18 |
스토어 게터를 기준으로 조건부로 b-테이블 열 표시/숨기기 (0) | 2023.06.18 |
Excel에서 대문자 분할 (0) | 2023.06.18 |
구체화된 보기를 항상 최신 상태로 유지하려면 어떻게 해야 합니까? (0) | 2023.06.18 |