গোষ্ঠী অনুসারে শীর্ষ মান প্রাপ্তি


95

এখানে একটি নমুনা ডেটা ফ্রেম রয়েছে:

d <- data.frame(
  x   = runif(90),
  grp = gl(3, 30)
) 

আমি প্রতিটি মানের জন্য dশীর্ষ 5 টির মান সহ সারিগুলি যুক্ত করার উপসেট চাই ।xgrp

বেস-আর ব্যবহার করে, আমার পদ্ধতির কিছু হবে:

ordered <- d[order(d$x, decreasing = TRUE), ]    
splits <- split(ordered, ordered$grp)
heads <- lapply(splits, head)
do.call(rbind, heads)
##              x grp
## 1.19 0.8879631   1
## 1.4  0.8844818   1
## 1.12 0.8596197   1
## 1.26 0.8481809   1
## 1.18 0.8461516   1
## 1.29 0.8317092   1
## 2.31 0.9751049   2
## 2.34 0.9269764   2
## 2.57 0.8964114   2
## 2.58 0.8896466   2
## 2.45 0.8888834   2
## 2.35 0.8706823   2
## 3.74 0.9884852   3
## 3.73 0.9837653   3
## 3.83 0.9375398   3
## 3.64 0.9229036   3
## 3.69 0.8021373   3
## 3.86 0.7418946   3

ব্যবহার করে dplyr, আমি এটি কাজ করবে বলে আশা করি:

d %>%
  arrange_(~ desc(x)) %>%
  group_by_(~ grp) %>%
  head(n = 5)

তবে এটি কেবল সামগ্রিক শীর্ষ 5 টি সারি দেয়।

পুরো রিটার্নের headজন্য অদলবদল ।top_nd

d %>%
  arrange_(~ desc(x)) %>%
  group_by_(~ grp) %>%
  top_n(n = 5)

আমি কীভাবে সঠিক উপসেট পাব?

উত্তর:


129

থেকে 1.0.0 dplyr , " slice_min()এবং slice_max()সর্বনিম্ন বা একটি পরিবর্তনশীল সর্বোচ্চ মান সঙ্গে সারি নির্বাচন করুন, বিভ্রান্তিকর কাছ থেকে দায়িত্ব নিয়ে top_n()."

d %>% group_by(grp) %>% slice_max(order_by = x, n = 5)
# # A tibble: 15 x 2
# # Groups:   grp [3]
#     x grp  
# <dbl> <fct>
#  1 0.994 1    
#  2 0.957 1    
#  3 0.955 1    
#  4 0.940 1    
#  5 0.900 1    
#  6 0.963 2    
#  7 0.902 2    
#  8 0.895 2    
#  9 0.858 2    
# 10 0.799 2    
# 11 0.985 3    
# 12 0.893 3    
# 13 0.886 3    
# 14 0.815 3    
# 15 0.812 3

প্রাক dplyr 1.0.0ব্যবহার top_n:

থেকে ?top_n, wtতর্ক সম্পর্কে :

অর্ডার দেওয়ার জন্য ব্যবহারযোগ্য ভেরিয়েবল [...] টিবিএল- এর শেষ ভেরিয়েবলের ডিফল্ট হয় "।

আপনার ডেটা সেটে সর্বশেষ ভেরিয়েবলটি "grp", যা আপনি র্যাঙ্ক করতে চান এমন ভেরিয়েবল নয় এবং এই কারণেই আপনার top_nপ্রয়াস "পুরো ডিটি প্রদান করে"। সুতরাং, আপনি যদি আপনার ডেটা সেটে "x" দ্বারা র‌্যাঙ্ক করতে চান তবে আপনাকে নির্দিষ্ট করতে হবে wt = x

d %>%
  group_by(grp) %>%
  top_n(n = 5, wt = x)

ডেটা:

set.seed(123)
d <- data.frame(
  x = runif(90),
  grp = gl(3, 30))

8
বন্ধুত্বের সম্পর্ক অগ্রাহ্য করার উপায় আছে কি?
মাতাস


41

data.tableখুব সহজ সঙ্গে খুব ...

library(data.table)
setorder(setDT(d), -x)[, head(.SD, 5), keyby = grp]

বা

setorder(setDT(d), grp, -x)[, head(.SD, 5), by = grp]

বা (বড় ডেটা সেট করার জন্য দ্রুত হওয়া উচিত কারণ .SDপ্রতিটি গ্রুপের জন্য কল এড়ানো )

setorder(setDT(d), grp, -x)[, indx := seq_len(.N), by = grp][indx <= 5]

সম্পাদনা: এখানে কীভাবে dplyrতুলনা করা যায় data.table(যদি কারও আগ্রহ থাকে)

set.seed(123)
d <- data.frame(
  x   = runif(1e6),
  grp = sample(1e4, 1e6, TRUE))

library(dplyr)
library(microbenchmark)
library(data.table)
dd <- copy(d)

microbenchmark(
  top_n = {d %>%
             group_by(grp) %>%
             top_n(n = 5, wt = x)},
  dohead = {d %>%
              arrange_(~ desc(x)) %>%
              group_by_(~ grp) %>%
              do(head(., n = 5))},
  slice = {d %>%
             arrange_(~ desc(x)) %>%
             group_by_(~ grp) %>%
             slice(1:5)},
  filter = {d %>% 
              arrange(desc(x)) %>%
              group_by(grp) %>%
              filter(row_number() <= 5L)},
  data.table1 = setorder(setDT(dd), -x)[, head(.SD, 5L), keyby = grp],
  data.table2 = setorder(setDT(dd), grp, -x)[, head(.SD, 5L), grp],
  data.table3 = setorder(setDT(dd), grp, -x)[, indx := seq_len(.N), grp][indx <= 5L],
  times = 10,
  unit = "relative"
)


#        expr        min         lq      mean     median        uq       max neval
#       top_n  24.246401  24.492972 16.300391  24.441351 11.749050  7.644748    10
#      dohead 122.891381 120.329722 77.763843 115.621635 54.996588 34.114738    10
#       slice  27.365711  26.839443 17.714303  26.433924 12.628934  7.899619    10
#      filter  27.755171  27.225461 17.936295  26.363739 12.935709  7.969806    10
# data.table1  13.753046  16.631143 10.775278  16.330942  8.359951  5.077140    10
# data.table2  12.047111  11.944557  7.862302  11.653385  5.509432  3.642733    10
# data.table3   1.000000   1.000000  1.000000   1.000000  1.000000  1.000000    10

একটি সামান্য দ্রুত data.tableসমাধান যোগ করা :

set.seed(123L)
d <- data.frame(
    x   = runif(1e8),
    grp = sample(1e4, 1e8, TRUE))
setDT(d)
setorder(d, grp, -x)
dd <- copy(d)

library(microbenchmark)
microbenchmark(
    data.table3 = d[, indx := seq_len(.N), grp][indx <= 5L],
    data.table4 = dd[dd[, .I[seq_len(.N) <= 5L], grp]$V1],
    times = 10L
)

সময় আউটপুট:

Unit: milliseconds
        expr      min       lq     mean   median        uq      max neval
 data.table3 826.2148 865.6334 950.1380 902.1689 1006.1237 1260.129    10
 data.table4 729.3229 783.7000 859.2084 823.1635  966.8239 1014.397    10

আরেকটি data.tableপদ্ধতি যুক্ত করা যা সামান্য দ্রুত হওয়া উচিত:dt <- setorder(setDT(dd), grp, -x); dt[dt[, .I[seq_len(.N) <= 5L], grp]$V1]
চিনসুন 12

@ চিনসুন 12 আমার অতিথি হন। এই সমাধানগুলি আবার বেনমার্ক করার আমার কাছে সময় নেই।
ডেভিড আরেনবুর্গ

data.tableআরও একটি পদ্ধতি সহজ যোগ করা:setDT(d)[order(-x),x[1:5],keyby = .(grp)]
তাও হু

@ টাওহু এটি প্রথম দুটি সমাধানের মতো অনেকটা। আমার মনে হয় না :মারবেhead
ডেভিড আরেনবুর্গ

@ ডেভিড আরেনবুর্গ হ্যাঁ , আমি আপনার সাথে একমত, আমি মনে করি সর্বাধিক পার্থক্যটি setorderদ্রুতorder
তও হু

34

আপনাকে headএকটি কলটিতে মোড়ানো দরকার do। নিম্নলিখিত কোড ইন, .বর্তমান গ্রুপ (বিবরণ দেখুন প্রতিনিধিত্ব করে ...মধ্যে doসহায়তা পৃষ্ঠা)।

d %>%
  arrange_(~ desc(x)) %>%
  group_by_(~ grp) %>%
  do(head(., n = 5))

আকরুন দ্বারা উল্লিখিত হিসাবে, sliceএকটি বিকল্প।

d %>%
  arrange_(~ desc(x)) %>%
  group_by_(~ grp) %>%
  slice(1:5)

যদিও আমি এটি জিজ্ঞাসা করি নি, সম্পূর্ণতার জন্য, একটি সম্ভাব্য data.tableসংস্করণ হ'ল (ফিক্সের জন্য @ অরণকে ধন্যবাদ):

setDT(d)[order(-x), head(.SD, 5), by = grp]

4
ধন্যবাদ আমি এই ফাংশন সম্পর্কে জানতাম না।
রিচি কটন

ধন্যবাদ ডেভিড আরেনবুর্গ তাড়াহুড়ো করে একটি পোস্ট পোস্ট করার পরে এটিই আসে। আমি বাজে কথা সরিয়েছি।
রিচি কটন

4
রিচি, এফডাব্লুআইডাব্লু আপনার কেবলমাত্র একটি ছোট সংযোজন দরকার:setDT(d)[order(-x), head(.SD, 5L), by=grp]
অরুণ ১৮

এই উত্তরটি কিছুটা পুরানো হলেও দ্বিতীয় অংশটি হ'ল মূর্তিযুক্ত উপায় যদি আপনি ড্রপ ~এবং ব্যবহার করেন arrangeএবং group_byপরিবর্তে arrange_এবংgroup_by_
মুডি_মডসকিপার

15

বেস বেসে আমার পদ্ধতির হবে:

ordered <- d[order(d$x, decreasing = TRUE), ]
ordered[ave(d$x, d$grp, FUN = seq_along) <= 5L,]

এবং dplyr ব্যবহার করে, এর সাথে যোগাযোগটি sliceসম্ভবত দ্রুততম, তবে আপনি এটি ব্যবহার করতে পারেন filterযা সম্ভবত ব্যবহারের চেয়ে দ্রুত হবে do(head(., 5)):

d %>% 
  arrange(desc(x)) %>%
  group_by(grp) %>%
  filter(row_number() <= 5L)

dplyr বেঞ্চমার্ক

set.seed(123)
d <- data.frame(
  x   = runif(1e6),
  grp = sample(1e4, 1e6, TRUE))

library(microbenchmark)

microbenchmark(
  top_n = {d %>%
             group_by(grp) %>%
             top_n(n = 5, wt = x)},
  dohead = {d %>%
              arrange_(~ desc(x)) %>%
              group_by_(~ grp) %>%
              do(head(., n = 5))},
  slice = {d %>%
             arrange_(~ desc(x)) %>%
             group_by_(~ grp) %>%
             slice(1:5)},
  filter = {d %>% 
              arrange(desc(x)) %>%
              group_by(grp) %>%
              filter(row_number() <= 5L)},
  times = 10,
  unit = "relative"
)

Unit: relative
   expr       min        lq    median        uq       max neval
  top_n  1.042735  1.075366  1.082113  1.085072  1.000846    10
 dohead 18.663825 19.342854 19.511495 19.840377 17.433518    10
  slice  1.000000  1.000000  1.000000  1.000000  1.000000    10
 filter  1.048556  1.044113  1.042184  1.180474  1.053378    10

@ অ্যাকরুনের filterঅতিরিক্ত ক্রিয়াকলাপ প্রয়োজন, যদিও আপনার sliceসংস্করণটি নেই ...
ডেভিড আরেনবুর্গ

4
আপনি জানেন কেন আপনি data.tableএখানে যুক্ত করেননি ;)
ডেভিড আরেনবুর্গ

4
আমি এটি জানি এবং আমি আপনাকে বলতে পারি: কারণ প্রশ্নটি বিশেষত একটি ডিসপ্লায়ার সমাধানের জন্য জিজ্ঞাসা করেছিল।
তালাত

4
আমি কেবল মজা করছিলাম ... এমনটি হয় না যে আপনি কখনও করেননি (ঠিক বিপরীত নির্দেশে)।
ডেভিড আরেনবুর্গ 4'15

@ ডেভিড আরেনবার্গ, আমি এটি "অবৈধ" বা কোনও ডেটা দেওয়ার মতো কিছু বলছিলাম না।ট্যাবল জবাব .. অবশ্যই আপনি এটি করতে পারেন এবং আপনার পছন্দ মতো কোনও মানদণ্ড সরবরাহ করতে পারেন :) বিটিডব্লিউ, আপনি যে প্রশ্নটির সাথে লিঙ্ক করেছেন সেটি একটি দুর্দান্ত উদাহরণ যেখানে dplyr বাক্য গঠনটি ডেটা.ট্যাবিলের চেয়ে আরও সুবিধাজনক (আমি জানি, সাবজেক্টিভ!)।
তালাত

1

top_n (ঢ = 1) এখনো প্রতি দলের জন্য একাধিক সারি ফিরে আসবে যদি ক্রম পরিবর্তনশীল প্রতিটি দলের মধ্যে অনন্য নয়। প্রতিটি গ্রুপের জন্য সঠিকভাবে একটি ঘটনা নির্বাচন করতে, প্রতিটি সারিতে একটি অনন্য ভেরিয়েবল যুক্ত করুন:

set.seed(123)
d <- data.frame(
  x   = runif(90),
  grp = gl(3, 30))

d %>%
  mutate(rn = row_number()) %>% 
  group_by(grp) %>%
  top_n(n = 1, wt = rn)

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