데이터 프레임에서 열 순서를 지정하여 그룹(사분위수, 분위수 등)을 신속하게 구성하는 방법
.order
그리고.sort
또는 로이 있습니까 벡터 또는 데이터 프레임을 그룹화(사분위 또는 분위수)하는 방법이 있습니까?저는 "매뉴얼" 솔루션을 가지고 있지만, 그룹 테스트를 거친 더 나은 솔루션이 있을 것입니다.
제 시도는 이렇습니다.
temp <- data.frame(name=letters[1:12], value=rnorm(12), quartile=rep(NA, 12))
temp
# name value quartile
# 1 a 2.55118169 NA
# 2 b 0.79755259 NA
# 3 c 0.16918905 NA
# 4 d 1.73359245 NA
# 5 e 0.41027113 NA
# 6 f 0.73012966 NA
# 7 g -1.35901658 NA
# 8 h -0.80591167 NA
# 9 i 0.48966739 NA
# 10 j 0.88856758 NA
# 11 k 0.05146856 NA
# 12 l -0.12310229 NA
temp.sorted <- temp[order(temp$value), ]
temp.sorted$quartile <- rep(1:4, each=12/4)
temp <- temp.sorted[order(as.numeric(rownames(temp.sorted))), ]
temp
# name value quartile
# 1 a 2.55118169 4
# 2 b 0.79755259 3
# 3 c 0.16918905 2
# 4 d 1.73359245 4
# 5 e 0.41027113 2
# 6 f 0.73012966 3
# 7 g -1.35901658 1
# 8 h -0.80591167 1
# 9 i 0.48966739 3
# 10 j 0.88856758 4
# 11 k 0.05146856 2
# 12 l -0.12310229 1
더 나은 접근 방식(청소기/더 빠른/한 줄)이 있습니까?감사합니다!
편리한 것이 있습니다.ntile
dplyr
의 수를 매우 할 수 . 하려는 *"" 의합니다를 합니다.
패키지를 로드하고(설치하지 않은 경우 먼저 설치) 사분위수 열을 추가합니다.
library(dplyr)
temp$quartile <- ntile(temp$value, 4)
또는 dplyr 구문을 사용하려면:
temp <- temp %>% mutate(quartile = ntile(value, 4))
두 경우 모두 결과는 다음과 같습니다.
temp
# name value quartile
#1 a -0.56047565 1
#2 b -0.23017749 2
#3 c 1.55870831 4
#4 d 0.07050839 2
#5 e 0.12928774 3
#6 f 1.71506499 4
#7 g 0.46091621 3
#8 h -1.26506123 1
#9 i -0.68685285 1
#10 j -0.44566197 2
#11 k 1.22408180 4
#12 l 0.35981383 3
데이터:
하고 "" 를 set.seed
무작위화를 재현할 수 있도록 하기 위해:
set.seed(123)
temp <- data.frame(name=letters[1:12], value=rnorm(12))
이 중 ㅇHmisc::cut2(value, g=4)
:
temp$quartile <- with(temp, cut(value,
breaks=quantile(value, probs=seq(0,1, by=0.25), na.rm=TRUE),
include.lowest=TRUE))
대체 수단은 다음과 같습니다.
temp$quartile <- with(temp, factor(
findInterval( val, c(-Inf,
quantile(val, probs=c(0.25, .5, .75)), Inf) , na.rm=TRUE),
labels=c("Q1","Q2","Q3","Q4")
))
첫 하는 부작용이 일'이라고 ' 일갈 수 이라면 2 '' 이라고하지만, '' 2 로를 하세요합니다.labels=
인에cut
이 :, 에 도 있습니다
temp$quartile <- factor(temp$quartile, levels=c("1","2","3","4") )
또는 더 이상 요인이 아니라 숫자 벡터가 아니라 작동 방식이 조금 더 빠르지만 조금 더 모호합니다.
temp$quartile <- as.numeric(temp$quartile)
추가하겠습니다.data.table
을 검색하는 @함) 즉을 들어 @BondedDust역:data.table
로): (
library(data.table)
setDT(temp)
temp[ , quartile := cut(value,
breaks = quantile(value, probs = 0:4/4),
labels = 1:4, right = FALSE)]
제가 해왔던 것보다 훨씬 더 나은(깨끗하고 빠르게) 것은 다음과 같습니다.
temp[ , quartile :=
as.factor(ifelse(value < quantile(value, .25), 1,
ifelse(value < quantile(value, .5), 2,
ifelse(value < quantile(value, .75), 3, 4))]
이 은 에서 점에 하십시오. 예를 들어 다음과 같이 실패합니다.rep(0:1, c(100, 1))
; 이 경우에 어떻게 할 것인지는 열려 있으니 당신에게 맡기겠습니다.
dplyr::ntile
이용하다, 이용하다, 이용하다, 이용하다, 이용하다, 이용하다, 이용.data.table
최적화는 보다 빠른 솔루션을 제공합니다.
library(data.table)
setDT(temp)
temp[order(value) , quartile := floor( 1 + 4 * (.I-1) / .N)]
아마 더 깨끗할 자격은 없지만, 더 빠르고 한 줄입니다.
더 큰 데이터 세트에 대한 타이밍
과 비교ntile
그리고.cut
위해서data.table
@docendo_discimus 와 @Michael Chirico 가 제안한 바와 같이.
library(microbenchmark)
library(dplyr)
set.seed(123)
n <- 1e6
temp <- data.frame(name=sample(letters, size=n, replace=TRUE), value=rnorm(n))
setDT(temp)
microbenchmark(
"ntile" = temp[, quartile_ntile := ntile(value, 4)],
"cut" = temp[, quartile_cut := cut(value,
breaks = quantile(value, probs = seq(0, 1, by=1/4)),
labels = 1:4, right=FALSE)],
"dt_ntile" = temp[order(value), quartile_ntile_dt := floor( 1 + 4 * (.I-1)/.N)]
)
제공:
Unit: milliseconds
expr min lq mean median uq max neval
ntile 608.1126 647.4994 670.3160 686.5103 691.4846 712.4267 100
cut 369.5391 373.3457 375.0913 374.3107 376.5512 385.8142 100
dt_ntile 117.5736 119.5802 124.5397 120.5043 124.5902 145.7894 100
를 .quantile()
딩합니다 합니다.cut()
.그렇게
set.seed(123)
temp <- data.frame(name=letters[1:12], value=rnorm(12), quartile=rep(NA, 12))
brks <- with(temp, quantile(value, probs = c(0, 0.25, 0.5, 0.75, 1)))
temp <- within(temp, quartile <- cut(value, breaks = brks, labels = 1:4,
include.lowest = TRUE))
제공:
> head(temp)
name value quartile
1 a -0.56047565 1
2 b -0.23017749 2
3 c 1.55870831 4
4 d 0.07050839 2
5 e 0.12928774 3
6 f 1.71506499 4
파티에 좀 늦어서 죄송합니다.다를 .cut2
제 데이터에 대해 max/min을 몰랐기 때문에 그룹이 동일하게 크기를 원했기 때문입니다.중복으로 표기된 이슈에서 cut2에 대해 읽었습니다(아래 링크).
library(Hmisc) #For cut2
set.seed(123) #To keep answers below identical to my random run
temp <- data.frame(name=letters[1:12], value=rnorm(12), quartile=rep(NA, 12))
temp$quartile <- as.numeric(cut2(temp$value, g=4)) #as.numeric to number the factors
temp$quartileBounds <- cut2(temp$value, g=4)
temp
결과:
> temp
name value quartile quartileBounds
1 a -0.56047565 1 [-1.265,-0.446)
2 b -0.23017749 2 [-0.446, 0.129)
3 c 1.55870831 4 [ 1.224, 1.715]
4 d 0.07050839 2 [-0.446, 0.129)
5 e 0.12928774 3 [ 0.129, 1.224)
6 f 1.71506499 4 [ 1.224, 1.715]
7 g 0.46091621 3 [ 0.129, 1.224)
8 h -1.26506123 1 [-1.265,-0.446)
9 i -0.68685285 1 [-1.265,-0.446)
10 j -0.44566197 2 [-0.446, 0.129)
11 k 1.22408180 4 [ 1.224, 1.715]
12 l 0.35981383 3 [ 0.129, 1.224)
temp$quartile <- ceiling(sapply(temp$value,function(x) sum(x-temp$value>=0))/(length(temp$value)/4))
이 기능을 사용해 보십시오.
getQuantileGroupNum <- function(vec, group_num, decreasing=FALSE) {
if(decreasing) {
abs(cut(vec, quantile(vec, probs=seq(0, 1, 1 / group_num), type=8, na.rm=TRUE), labels=FALSE, include.lowest=T) - group_num - 1)
} else {
cut(vec, quantile(vec, probs=seq(0, 1, 1 / group_num), type=8, na.rm=TRUE), labels=FALSE, include.lowest=T)
}
}
> t1 <- runif(7)
> t1
[1] 0.4336094 0.2842928 0.5578876 0.2678694 0.6495285 0.3706474 0.5976223
> getQuantileGroupNum(t1, 4)
[1] 2 1 3 1 4 2 4
> getQuantileGroupNum(t1, 4, decreasing=T)
[1] 3 4 2 4 1 3 1
사용하는 데 문제가 많아서 좀 더 견고한 것 같은 버전을 제안하고 싶습니다.quantile()
휴식시간에cut()
내 데이터셋에.사용하고 있습니다.ntile
의 기능을plyr
, 하지만 그것은 또한 함께 작동합니다.ecdf
입력으로
temp[, `:=`(quartile = .bincode(x = ntile(value, 100), breaks = seq(0,100,25), right = TRUE, include.lowest = TRUE)
decile = .bincode(x = ntile(value, 100), breaks = seq(0,100,10), right = TRUE, include.lowest = TRUE)
)]
temp[, `:=`(quartile = .bincode(x = ecdf(value)(value), breaks = seq(0,1,0.25), right = TRUE, include.lowest = TRUE)
decile = .bincode(x = ecdf(value)(value), breaks = seq(0,1,0.1), right = TRUE, include.lowest = TRUE)
)]
그것이 맞습니까?
원래 값이 일부 값으로 군집되어 있으면 ntile()을 사용해야 합니다.동일한 크기의 그룹을 만들기 위해 원래 값이 같은 행을 다른 그룹에 할당합니다.이것은 바람직하지 않을 수 있습니다.
저는 개인의 점수가 일정한 값으로 모여 있는 경우가 있었는데, 원점수가 같은 개인을 같은 그룹에 두는 것이 중요했습니다(예: 시험 점수에 따라 그룹에 학생을 할당하는 것).ntile ()는 동일한 점수를 가진 개체를 다른 그룹(이 경우 unfair)에 할당하지만 분위수 ()이 있는 절단 ()는 할당하지 않습니다(단, 그룹의 크기는 대략 동일합니다).
library(dplyr)
library(reshape2)
library(ggplot2)
# awkward data: cannot be fairly and equally divided into quartiles or quintiles
# (similar results are obtained from more realistic cases of clustered values)
example <- data.frame(id = 1:49, x = c(rep(1:7, each=7))) %>%
mutate(ntileQuartile = ntile(x, 4),
cutQuartile = cut(x, breaks=quantile(x, seq(0, 1, by=1/4)),
include.lowest=T, label=1:4),
ntileQuintile = ntile(x, 5),
cutQuintile = cut(x, breaks=quantile(x, seq(0, 1, by=1/5)),
include.lowest=T, label=1:5))
# graph: x axis is original score, colour is group allocation
# ntile creates equal groups, but some values of original score are split
# into separate groups. cut creates different sized groups, but score
# exactly determines the group.
melt(example, id.vars=c("id", "x"),
variable.name = "method", value.name="groupNumber") %>%
ggplot(aes(x, fill=groupNumber)) +
geom_histogram(colour="black", bins=13) +
facet_wrap(vars(method))
더 빠른 방법이 있을 수도 있지만, 저는 그렇게 할 것입니다.
a <- rnorm(100) # Our data
q <- quantile(a) # You can supply your own breaks, see ?quantile
# Define a simple function that checks in which quantile a number falls
getQuant <- function(x)
{
for (i in 1:(length(q)-1))
{
if (x>=q[i] && x<q[i+1])
break;
}
i
}
# Apply the function to the data
res <- unlist(lapply(as.matrix(a), getQuant))
언급URL : https://stackoverflow.com/questions/4126326/how-to-quickly-form-groups-quartiles-deciles-etc-by-ordering-columns-in-a
'programing' 카테고리의 다른 글
Spring Security Expressions에서 정적 메서드를 호출합니까? (0) | 2023.10.14 |
---|---|
스위치 내부에 LIKE가 있는 MySQL의 선택 쿼리 (0) | 2023.10.14 |
Panda 열 바인딩(cbind) 데이터 프레임 두 개 (0) | 2023.10.14 |
리눅스 커널 버전을 확인할 수 있는 매크로 정의가 있습니까? (0) | 2023.10.14 |
입력유형="file" set base64 이미지 데이터 (0) | 2023.10.14 |