প্রতিটি সারির জন্য সর্বাধিক মানের কলামের নাম ফেরত দিন


100

আমার এক কর্মচারী রয়েছে এবং আমার জানা দরকার যে তারা প্রায়শই কোন বিভাগে থাকেন। বিভাগের নামের বিরুদ্ধে কর্মচারী আইডি ট্যাবুলেটেড করা তুচ্ছ, তবে ফ্রিকোয়েন্সি টেবিল থেকে রোস্টার গণনা সংখ্যার চেয়ে বিভাগের নাম ফিরিয়ে দেওয়া কৌতুকপূর্ণ। নীচে একটি সাধারণ উদাহরণ (কলামের নাম = বিভাগ, সারি নাম = কর্মচারী আইডি)।

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

আপনার প্রকৃত তথ্য কত বড়?
অরুণ

4
@ অরুন> ম্লান (পরীক্ষা) [1] 26746 18
ডেমভিয়ানা

6
একটি উত্সাহব্যঞ্জক সাধারণীকরণ বৃহত্তম হবে এন মান 'সারি প্রতি কলাম নামে
হ্যাক-আর

উত্তর:


103

আপনার ডেটা ব্যবহার করে একটি বিকল্প (ভবিষ্যতের রেফারেন্সের জন্য, পুনরায় উত্পাদনযোগ্য 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 

আমার যদি দুটি সমান কলাম থাকে তবে আমি সাধারণত প্রথমটি চয়ন করি। এটি সীমান্তের মামলা যা আমার পরিসংখ্যান বিশ্লেষণকে বিরক্ত করে না।
ডিএমভিয়ানা

4
@ ডিএমভিয়ানা - ব্যবহার which.maxকরা ভাল হবে তখন।
থেটমেল

আমি ধরে নিচ্ছি যে অর্ডারটি সংরক্ষিত আছে, তাই আমি এই ভেক্টরটির সাথে একটি নতুন কলাম তৈরি করতে পারি যা কর্মীদের আইডিতে সঠিকভাবে সারিবদ্ধ হবে। এটা কি ঠিক?
ডিএমভিয়ানা

applyপরিবর্তিত data.frameকরতে matrixঅভ্যন্তরীণভাবে। আপনি এই মাত্রাগুলিতে পারফরম্যান্সের পার্থক্য দেখতে পাবেন না।
অরুণ

4
@ পঙ্কজকৌন্ডল - স্বতন্ত্র মূল্যবোধ ধরে নিয়ে, এটি সম্পর্কেcolnames(DF)[max.col(replace(DF, cbind(seq_len(nrow(DF)), max.col(DF,ties.method="first")), -Inf), "first")]
থেটমেল

15

আপনি যদি কোনও 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স্কেলগুলি খুব ভাল pretty


সম্পাদনা করুন: যদি সর্বোচ্চ আইডির কোনওটি ঠিক থাকে তবে:

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"]

আমি আসলে যত্ন নিই না যদি এটি প্রথম বা শেষ সর্বোচ্চ। আমি প্রথমে সরলতার জন্য যাচ্ছি, তবে আমি নিশ্চিত যে ভবিষ্যতে একটি ডেটা টেবিল সমাধান কার্যকর হবে, ধন্যবাদ!
dmvianna

11

একটি সমাধান হতে পারে যে সমস্ত বিভাগকে এক কলামে বিস্তৃত থেকে দীর্ঘতর করে তারিখটি পুনরায় আকার দেওয়া এবং অন্যটিতে গণনা করা, নিয়োগকর্তার আইডি দ্বারা গ্রুপ (এই ক্ষেত্রে, সারি নম্বর) এবং তারপরে বিভাগ (গুলি) এর সাথে ফিল্টার করা সর্বাধিক মান। এই পদ্ধতির সাথে সম্পর্ক পরিচালনা করার জন্যও বেশ কয়েকটি বিকল্প রয়েছে।

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.

11

উপরের পরামর্শগুলির উপর ভিত্তি করে, নিম্নলিখিত 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")]

@ লুশ্যাংয়ের পরামর্শ অনুসারে, আমাদের যদি সবচেয়ে ছোট মানটির কলামের নাম প্রয়োজন, তবে কেবল একটিটি ব্যবহার করা দরকার -.SD:

DT[, col_min := colnames(.SD)[max.col(-.SD, ties.method = "first")]]

আমার অনুরূপ প্রয়োজনীয়তা ছিল তবে প্রতিটি সারিটির সর্বনিম্ন মান থাকা কলামের নামটি পেতে চাই ..... আমাদের আর-তে min.col আছে বলে মনে হচ্ছে না ..... আপনি কি জানতেন সমতুল্য সমাধানটি কী হবে ?
ব্যবহারকারী 1412

হাই @ ইউজার 1412। আপনার আকর্ষণীয় প্রশ্নের জন্য ধন্যবাদ। which.minদেখতে দেখতে এমন কিছু ব্যবহার করা : DT[, MIN := colnames(.SD)[apply(.SD,1,which.min)]]বা DT[, MIN2 := colnames(.SD)[which.min(.SD)], by = 1:nrow(DT)]উপরে ডামি ডেটা ব্যবহার করা ছাড়া আমার এখনই কোনও ধারণা নেই । এটি বন্ধন বিবেচনা করে না এবং কেবল প্রথম সর্বনিম্ন প্রদান করে। হতে পারে একটি পৃথক প্রশ্ন জিজ্ঞাসা বিবেচনা করুন। আপনি কী উত্তর পেতে হবে তা আমি জানতে আগ্রহী হবে।
ভ্যালেন্টিন

4
একটি কৌতুক পেতে ন্যূনতম কলাম max.col মধ্যে data.frame নেতিবাচক পাঠাচ্ছে, মত: colnames(.SD)[max.col(-.SD, ties.method="first")]
লুশাং

6

একটি dplyrসমাধান:

ধারণা:

  • একটি কলাম হিসাবে সারি যোগ করুন
  • দীর্ঘ বিন্যাসে পুনরায় আকার দিন
  • প্রতিটি গ্রুপে সর্বোচ্চ জন্য ফিল্টার

কোড:

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

4
উপরোক্ত এই পদ্ধতির এবং শাবাবের উত্তরের মধ্যে পার্থক্য সম্পর্কে আপনি মন্তব্য করতে পারেন? তারা আমার সম্পর্কে একই চেহারা।
গ্রেগর থমাস

2

একটি সাধারণ 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

2

এর একটি বিকল্প 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     

নমুনা তথ্য:

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))

0

এখানে একটি উত্তর যা ডেটা.টিটেবলের সাথে কাজ করে এবং সহজ। এটি আপনার ডেটা ধরে নেয়। টেবিলটির নাম দেওয়া হয়েছে 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)আপনার কলামের নামগুলি দিয়ে


কলামের মানগুলিতে বিদ্যমান এনএ মানগুলি কীভাবে উপেক্ষা করবেন সে সম্পর্কে কেউ সাহায্য করতে পারেন
পার্থ সার্থী
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.