각 행에 대해 가장 큰 값의 열 이름을 반환합니다.
저는 직원 명단을 가지고 있고, 그들이 어느 부서에서 가장 자주 근무하는지 알아야 합니다.부서 이름에 대해 직원 ID를 표로 표시하는 것은 사소한 일이지만, 빈도 표에서 로스터 수가 아닌 부서 이름을 반환하는 것이 더 쉽습니다.아래의 간단한 예(열 이름 = 부서, 행 이름 = 직원 ID)입니다.
DF <- matrix(sample(1:9,9),ncol=3,nrow=3)
DF <- as.data.frame.matrix(DF)
> DF
V1 V2 V3
1 2 7 9
2 8 3 6
3 1 5 4
이제 어떻게 해야 합니까?
> DF2
RE
1 V3
2 V1
3 V2
데이터를 사용하는 단일 옵션(향후 참조를 위해 사용)set.seed()
예를 들면,sample
재현 가능):
DF <- data.frame(V1=c(2,8,1),V2=c(7,3,5),V3=c(9,6,4))
colnames(DF)[apply(DF,1,which.max)]
[1] "V3" "V1" "V2"
사용보다 빠른 솔루션apply
지도 모른다max.col
:
colnames(DF)[max.col(DF,ties.method="first")]
#[1] "V3" "V1" "V2"
...어디에ties.method
의 하나가 될 수 있습니다."random"
"first"
또는"last"
따라서 최대 열과 동일한 열이 두 개 있는 경우 당연히 문제가 발생합니다.이 경우 일부 행에 대해 둘 이상의 결과가 발생하기 때문에 어떤 작업을 수행할지 잘 모르겠습니다.예:
DF <- data.frame(V1=c(2,8,1),V2=c(7,3,5),V3=c(7,6,4))
apply(DF,1,function(x) which(x==max(x)))
[[1]]
V2 V3
2 3
[[2]]
V1
1
[[3]]
V2
2
한 가지 해결책은 모든 부서를 하나의 열에 넣고 다른 열에 카운트하는 날짜를 너비에서 길이로 재구성한 다음 고용주 ID(이 경우 행 번호)로 그룹화한 다음 최대값을 사용하여 부서로 필터링하는 것입니다.이 접근 방식과의 관계를 처리하는 데에도 몇 가지 옵션이 있습니다.
library(tidyverse)
# sample data frame with a tie
df <- data_frame(V1=c(2,8,1),V2=c(7,3,5),V3=c(9,6,5))
# If you aren't worried about ties:
df %>%
rownames_to_column('id') %>% # creates an ID number
gather(dept, cnt, V1:V3) %>%
group_by(id) %>%
slice(which.max(cnt))
# A tibble: 3 x 3
# Groups: id [3]
id dept cnt
<chr> <chr> <dbl>
1 1 V3 9.
2 2 V1 8.
3 3 V2 5.
# If you're worried about keeping ties:
df %>%
rownames_to_column('id') %>%
gather(dept, cnt, V1:V3) %>%
group_by(id) %>%
filter(cnt == max(cnt)) %>% # top_n(cnt, n = 1) also works
arrange(id)
# A tibble: 4 x 3
# Groups: id [3]
id dept cnt
<chr> <chr> <dbl>
1 1 V3 9.
2 2 V1 8.
3 3 V2 5.
4 3 V3 5.
# If you're worried about ties, but only want a certain department, you could use rank() and choose 'first' or 'last'
df %>%
rownames_to_column('id') %>%
gather(dept, cnt, V1:V3) %>%
group_by(id) %>%
mutate(dept_rank = rank(-cnt, ties.method = "first")) %>% # or 'last'
filter(dept_rank == 1) %>%
select(-dept_rank)
# A tibble: 3 x 3
# Groups: id [3]
id dept cnt
<chr> <chr> <dbl>
1 2 V1 8.
2 3 V2 5.
3 1 V3 9.
# if you wanted to keep the original wide data frame
df %>%
rownames_to_column('id') %>%
left_join(
df %>%
rownames_to_column('id') %>%
gather(max_dept, max_cnt, V1:V3) %>%
group_by(id) %>%
slice(which.max(max_cnt)),
by = 'id'
)
# A tibble: 3 x 6
id V1 V2 V3 max_dept max_cnt
<chr> <dbl> <dbl> <dbl> <chr> <dbl>
1 1 2. 7. 9. V3 9.
2 2 8. 3. 6. V1 8.
3 3 1. 5. 5. V2 5.
관심이 있는 경우data.table
해결책, 여기 하나 있습니다.당신은 첫 번째 최대치의 아이디를 받는 것을 선호하기 때문에 조금 까다롭습니다.당신이 마지막 최대치를 원한다면 훨씬 더 쉽습니다.그럼에도 불구하고, 그것은 그렇게 복잡하지 않고 빠릅니다!
여기 당신의 치수(26746 * 18)에 대한 데이터를 생성했습니다.
데이터.
set.seed(45)
DF <- data.frame(matrix(sample(10, 26746*18, TRUE), ncol=18))
data.table
답변:
require(data.table)
DT <- data.table(value=unlist(DF, use.names=FALSE),
colid = 1:nrow(DF), rowid = rep(names(DF), each=nrow(DF)))
setkey(DT, colid, value)
t1 <- DT[J(unique(colid), DT[J(unique(colid)), value, mult="last"]), rowid, mult="first"]
벤치마킹:
# data.table solution
system.time({
DT <- data.table(value=unlist(DF, use.names=FALSE),
colid = 1:nrow(DF), rowid = rep(names(DF), each=nrow(DF)))
setkey(DT, colid, value)
t1 <- DT[J(unique(colid), DT[J(unique(colid)), value, mult="last"]), rowid, mult="first"]
})
# user system elapsed
# 0.174 0.029 0.227
# apply solution from @thelatemail
system.time(t2 <- colnames(DF)[apply(DF,1,which.max)])
# user system elapsed
# 2.322 0.036 2.602
identical(t1, t2)
# [1] TRUE
이러한 차원의 데이터에서 약 11배 더 빠르며,data.table
비늘도 꽤 잘 잡힙니다.
편집: 최대 ID 중 하나라도 문제가 없으면 다음을 수행합니다.
DT <- data.table(value=unlist(DF, use.names=FALSE),
colid = 1:nrow(DF), rowid = rep(names(DF), each=nrow(DF)))
setkey(DT, colid, value)
t1 <- DT[J(unique(colid)), rowid, mult="last"]
위의 제안에 기초하여, 다음과 같은 것들이 있습니다.data.table
솔루션은 매우 빠르게 작동했습니다.
library(data.table)
set.seed(45)
DT <- data.table(matrix(sample(10, 10^7, TRUE), ncol=10))
system.time(
DT[, col_max := colnames(.SD)[max.col(.SD, ties.method = "first")]]
)
#> user system elapsed
#> 0.15 0.06 0.21
DT[]
#> V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 col_max
#> 1: 7 4 1 2 3 7 6 6 6 1 V1
#> 2: 4 6 9 10 6 2 7 7 1 3 V4
#> 3: 3 4 9 8 9 9 8 8 6 7 V3
#> 4: 4 8 8 9 7 5 9 2 7 1 V4
#> 5: 4 3 9 10 2 7 9 6 6 9 V4
#> ---
#> 999996: 4 6 10 5 4 7 3 8 2 8 V3
#> 999997: 8 7 6 6 3 10 2 3 10 1 V6
#> 999998: 2 3 2 7 4 7 5 2 7 3 V4
#> 999999: 8 10 3 2 3 4 5 1 1 4 V2
#> 1000000: 10 4 2 6 6 2 8 4 7 4 V1
또한 항상 특정 열을 지정할 수 있는 이점도 있습니다..SD
에서 그들을 언급함으로써 고려해야 합니다..SDcols
:
DT[, MAX2 := colnames(.SD)[max.col(.SD, ties.method="first")], .SDcols = c("V9", "V10")]
@lwshang이 제안한 것처럼 가장 작은 값의 열 이름이 필요한 경우에는 다음을 사용하면 됩니다.-.SD
:
DT[, col_min := colnames(.SD)[max.col(-.SD, ties.method = "first")]]
하나의 옵션dplyr 1.0.0
다음이 될 수 있습니다.
DF %>%
rowwise() %>%
mutate(row_max = names(.)[which.max(c_across(everything()))])
V1 V2 V3 row_max
<dbl> <dbl> <dbl> <chr>
1 2 7 9 V3
2 8 3 6 V1
3 1 5 4 V2
어떤 상황에서는, 사용하는 것이 더 안전할 수 있습니다.pmap()
(계속)purrr
):
DF %>%
mutate(row_max = pmap_chr(across(everything()), ~ names(c(...)[which.max(c(...))])))
표본 데이터:
DF <- structure(list(V1 = c(2, 8, 1), V2 = c(7, 3, 5), V3 = c(9, 6,
4)), class = "data.frame", row.names = c(NA, -3L))
A dplyr
솔루션:
아이디어:
- 행 ID를 열로 추가
- 장문의 형식으로 다시 짜다
- 각 그룹의 최대값에 대한 필터
코드:
DF = data.frame(V1=c(2,8,1),V2=c(7,3,5),V3=c(9,6,4))
DF %>%
rownames_to_column() %>%
gather(column, value, -rowname) %>%
group_by(rowname) %>%
filter(rank(-value) == 1)
결과:
# A tibble: 3 x 3
# Groups: rowname [3]
rowname column value
<chr> <chr> <dbl>
1 2 V1 8
2 3 V2 5
3 1 V3 9
할 수 .n
∙ 예에 예:n=2
:
DF %>%
rownames_to_column() %>%
gather(column, value, -rowname) %>%
group_by(rowname) %>%
mutate(rk = rank(-value)) %>%
filter(rk <= 2) %>%
arrange(rowname, rk)
결과:
# A tibble: 6 x 4
# Groups: rowname [3]
rowname column value rk
<chr> <chr> <dbl> <dbl>
1 1 V3 9 1
2 1 V2 7 2
3 2 V1 8 1
4 2 V3 6 2
5 3 V2 5 1
6 3 V3 4 2
이것은 빠르고 간단한 정갈한 역 솔루션으로, 어떤 열의 하위 집합에도 쉽게 적용할 수 있습니다.data.frame
도 아래버다사음다니용합을전도다를 사용합니다.ifelse
모든 열이 0인 경우 결측값을 추가합니다.결측값은 예를 들어, 누군가가 이 값을 사용하여 핫 인코딩된 열을 재결합하려는 경우 유용합니다.문제의 데이터에서 작동하지만, 여기 단일 핫 인코딩 데이터 세트의 예가 있습니다.
data <- data.frame(
oh_a = c(1,0,0,1,0,0)
,oh_b = c(0,1,1,0,0,0)
,oh_c = c(0,0,0,0,1,0)
,d = c("l","m","n","o","p","q"))
f <- function(x){ifelse(rowSums(x)==0, NA, names(x)[max.col(x, "first")])}
data %>%
mutate(transformed = f(across(starts_with("oh"))))
출력:
oh_a oh_b oh_c d transformed
1 1 0 0 l oh_a
2 0 1 0 m oh_b
3 0 1 0 n oh_b
4 1 0 0 o oh_a
5 0 0 1 p oh_c
6 0 0 0 q <NA>
단한.for
루프는 유용할 수도 있습니다.
> df<-data.frame(V1=c(2,8,1),V2=c(7,3,5),V3=c(9,6,4))
> df
V1 V2 V3
1 2 7 9
2 8 3 6
3 1 5 4
> df2<-data.frame()
> for (i in 1:nrow(df)){
+ df2[i,1]<-colnames(df[which.max(df[i,])])
+ }
> df2
V1
1 V3
2 V1
3 V2
여기 data.table로 작동하고 더 간단한 답변이 있습니다.에서는 data이 "데이터 테이블"이라고 합니다.yourDF
:
j1 <- max.col(yourDF[, .(V1, V2, V3, V4)], "first")
yourDF$newCol <- c("V1", "V2", "V3", "V4")[j1]
를 바꿉니다.("V1", "V2", "V3", "V4")
그리고.(V1, V2, V3, V4)
이것은 빠릅니다.
with(DF, {
names(DF)[(V1 > V2 & V1 > V3) * 1 + (V2 > V3 & V2 > V1) * 2 + (V3 > V1 & V3 > V2)*3]
})
언급URL : https://stackoverflow.com/questions/17735859/for-each-row-return-the-column-name-of-the-largest-value
'programing' 카테고리의 다른 글
하위 MSBuild.exe 프로세스를 성공적으로 시작하거나 연결하지 못했습니다.MSBuild.exe를 확인합니다. (0) | 2023.06.26 |
---|---|
통계 모드를 찾는 방법은 무엇입니까? (0) | 2023.06.26 |
소수(s,p) 또는 숫자(s,p)? (0) | 2023.06.26 |
Unit-Testing의 assertRaises()를 NoneType 객체와 함께 적절하게 사용하는 방법 (0) | 2023.06.26 |
어떤 숫자가 다른 숫자로 구분되는지 어떻게 확인합니까? (0) | 2023.06.21 |