Data.table: Keyby / عن طريق عدم إرجاع مجموعات فريدة مع مجموعات فرعية

تم إنشاؤها على ٣١ مارس ٢٠١٨  ·  4تعليقات  ·  مصدر: Rdatatable/data.table

يوجد أدناه مثال بسيط حيث لا يقوم keyby (أيضًا بواسطة) بإرجاع مجموعات فريدة مع مجموعات فرعية.
ومع ذلك ، بمجرد إزالة الضبط الفرعي ، يعمل keyby بشكل صحيح.

library(data.table)
# data.table 1.10.5 IN DEVELOPMENT built 2018-03-21 23:49:00 UTC; travis
#  The fastest way to learn (by data.table authors): https://www.datacamp.com/courses/data-analysis-the-data-table-way
#  Documentation: ?data.table, example(data.table) and browseVignettes("data.table")
#  Release notes, videos and slides: http://r-datatable.com

# small dataset
dat <- data.table(Group = rep(c("All", "Not All"), times = 4), count = 1:8, ID = rep(1:2, each = 4))

# keyby returning non unique IDs with subset
dat[Group == "All" ,lapply(.SD, function(x) sum(x, na.rm = TRUE)), .SDcols= c("count"), keyby = ID, verbose = TRUE]
# Creating new index 'Group'
# Creating index Group done in ... 0.001sec 
# Optimized subsetting with index 'Group'
# on= matches existing index, using index
# Starting bmerge ...done in 0.000sec 
# i clause present and columns used in by detected, only these subset: ID 
# Finding groups using forderv ... 0.000sec 
# Finding group sizes from the positions (can be avoided to save RAM) ... 0.000sec 
# lapply optimization changed j from 'lapply(.SD, function(x) sum(x, na.rm = TRUE))' to 'list(..FUN1(count))'
# GForce is on, left j unchanged
# Old mean optimization is on, left j unchanged.
# Making each group and running j (GForce FALSE) ... 
#   collecting discontiguous groups took 0.000s for 2 groups
#   eval(j) took 0.000s for 2 calls
# 0.000sec 
#    ID count
# 1:  1     4
# 2:  1    12

# keyby working fine without subset
dat[,lapply(.SD, function(x) sum(x, na.rm = TRUE)), .SDcols= c("count"), keyby = ID] 
# Finding groups using forderv ... 0.000sec 
# Finding group sizes from the positions (can be avoided to save RAM) ... 0.000sec 
# lapply optimization changed j from 'lapply(.SD, function(x) sum(x, na.rm = TRUE))' to 'list(..FUN1(count))'
# GForce is on, left j unchanged
# Old mean optimization is on, left j unchanged.
# Making each group and running j (GForce FALSE) ... 
#   memcpy contiguous groups took 0.000s for 2 groups
#   eval(j) took 0.000s for 2 calls
# 0.000sec 
#    ID count
# 1:  1    10
# 2:  2    26

sessionInfo()
R version 3.4.4 (2018-03-15)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Debian GNU/Linux 9 (stretch)
Matrix products: default
BLAS: /usr/lib/openblas-base/libblas.so.3
LAPACK: /usr/lib/libopenblasp-r0.2.19.so
locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=C             
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     
other attached packages:
[1] data.table_1.10.5
loaded via a namespace (and not attached):
[1] compiler_3.4.4
bug dev

التعليق الأكثر فائدة

توافق على أنه خطأ.

للسجل ، الكود الموصى به في هذه الحالة هو:

dat[Group == "All", lapply(.SD, sum, na.rm = TRUE), .SDcols= c("count"), keyby = ID]

والذي يعطي الإجابة الصحيحة لأن هذا الإصدار سينشط GForce والخطأ غير موجود في هذه الحالة.

بالطبع هذا لا يساعد إذا كان الرمز الفعلي الخاص بك لا يمكن حذفه على هذا النحو.

من المثير للاهتمام أنه إذا مررنا صفوف المجموعة الفرعية مباشرة ، فستعمل الكود:

dat[c(1, 3, 5, 7),
    lapply(.SD, function(x) sum(x, na.rm = TRUE)),
    .SDcols= "count", keyby = ID, verbose = TRUE]
# i clause present and columns used in by detected, only these subset: ID 
# Finding groups using forderv ... 0.000sec 
# Finding group sizes from the positions (can be avoided to save RAM) ... 0.000sec 
# lapply optimization changed j from 'lapply(.SD, function(x) sum(x, na.rm = TRUE))' to 'list(..FUN1(count))'
# GForce is on, left j unchanged
# Old mean optimization is on, left j unchanged.
# Making each group and running j (GForce FALSE) ... 
#   collecting discontiguous groups took 0.000s for 2 groups
#   eval(j) took 0.000s for 2 calls
# 0.000sec 
#    ID count
# 1:  1     4
# 2:  2    12

أرى الاختلاف التالي في الناتج verbose :

الاشتراك الأمثل مع فهرس "المجموعة"

قادني هذا إلى التثبيت من CRAN ؛ يعمل الكود بدون أخطاء على 1.10.4-3 .

لذا أعتقد أن هذا شيء من عمل MarkusBonsch على تحسين المجموعة الفرعية؟

أرى أيضًا نفس الخطأ إذا جعلنا الصلة صريحة:

dat[.('All'), on = 'Group',
    lapply(.SD, function(x) sum(x, na.rm = TRUE)),
    .SDcols= "count", keyby = ID]
#    ID count
# 1:  1     4
# 2:  1    12

لكن النسخة ذات المفاتيح جيدة:

setkey(dat, Group)
dat[.('All'), 
    lapply(.SD, function(x) sum(x, na.rm = TRUE)),
    .SDcols= "count", keyby = ID]#    ID count
# 1:  1     4
# 2:  2    12

ال 4 كومينتر

توافق على أنه خطأ.

للسجل ، الكود الموصى به في هذه الحالة هو:

dat[Group == "All", lapply(.SD, sum, na.rm = TRUE), .SDcols= c("count"), keyby = ID]

والذي يعطي الإجابة الصحيحة لأن هذا الإصدار سينشط GForce والخطأ غير موجود في هذه الحالة.

بالطبع هذا لا يساعد إذا كان الرمز الفعلي الخاص بك لا يمكن حذفه على هذا النحو.

من المثير للاهتمام أنه إذا مررنا صفوف المجموعة الفرعية مباشرة ، فستعمل الكود:

dat[c(1, 3, 5, 7),
    lapply(.SD, function(x) sum(x, na.rm = TRUE)),
    .SDcols= "count", keyby = ID, verbose = TRUE]
# i clause present and columns used in by detected, only these subset: ID 
# Finding groups using forderv ... 0.000sec 
# Finding group sizes from the positions (can be avoided to save RAM) ... 0.000sec 
# lapply optimization changed j from 'lapply(.SD, function(x) sum(x, na.rm = TRUE))' to 'list(..FUN1(count))'
# GForce is on, left j unchanged
# Old mean optimization is on, left j unchanged.
# Making each group and running j (GForce FALSE) ... 
#   collecting discontiguous groups took 0.000s for 2 groups
#   eval(j) took 0.000s for 2 calls
# 0.000sec 
#    ID count
# 1:  1     4
# 2:  2    12

أرى الاختلاف التالي في الناتج verbose :

الاشتراك الأمثل مع فهرس "المجموعة"

قادني هذا إلى التثبيت من CRAN ؛ يعمل الكود بدون أخطاء على 1.10.4-3 .

لذا أعتقد أن هذا شيء من عمل MarkusBonsch على تحسين المجموعة الفرعية؟

أرى أيضًا نفس الخطأ إذا جعلنا الصلة صريحة:

dat[.('All'), on = 'Group',
    lapply(.SD, function(x) sum(x, na.rm = TRUE)),
    .SDcols= "count", keyby = ID]
#    ID count
# 1:  1     4
# 2:  1    12

لكن النسخة ذات المفاتيح جيدة:

setkey(dat, Group)
dat[.('All'), 
    lapply(.SD, function(x) sum(x, na.rm = TRUE)),
    .SDcols= "count", keyby = ID]#    ID count
# 1:  1     4
# 2:  2    12

بفضلcathine للإبلاغ وMichaelChirico للتحقيق.
السبب الأساسي هو سلوك عربات التي تجرها الدواب لنسخة الانضمام كما أشار مايكل:
dat[.('All'), on = 'Group', lapply(.SD, function(x) sum(x, na.rm = TRUE)), .SDcols= "count", keyby = ID]

من المحتمل أن يتم حلها عند حل هذه المشكلة رقم 2591.
في تحسين التقسيم الجديد ، تتم إعادة توجيه المجموعات الفرعية إلى جزء الانضمام من data.table ، لذلك يؤثر هذا الخطأ الآن على المجموعات الفرعية الآن بالإضافة إلى عمليات الانضمام. سأحاول التحقيق في أسرع وقت ممكن إذا كان بإمكاني حل المشكلة.
حتى ذلك الحين ، يمكنك اللجوء إلى
dat[Group == "All"][ ,lapply(.SD, function(x) sum(x, na.rm = TRUE)), .SDcols= c("count"), keyby = ID, verbose = TRUE] على سبيل المثال.
نأسف للإزعاج.

شكرا @ كاثين! تم التأكيد على أن هذا مخصص للمطورين فقط ويمكن تخفيفه باستخدام options(datatable.optimize=2) نظرًا لأن المشكلة تبدو في المستوى 3 من التحسين. أتساءل كيف نجح هذا في اجتياز الاختبارات!
حتى الأمثلة الأبسط من جهة اتصال أخرى أبلغت أيضًا:

> DT = data.table(
    id = c("a","a","a","b","b","c","c","d","d"),
    group = c(1,1,1,1,1,2,2,2,2),
    num = 1)
> DT[, uniqueN(id), by=group]          # ok 
   group    V1
   <num> <int>
1:     1     2
2:     2     2
> DT[num==1, uniqueN(id), by=group]    # group column wrong
   group    V1
   <num> <int>
1:     1     2
2:     1     2
> options(datatable.optimize=2)
> DT[num==1, uniqueN(id), by=group]    # ok
   group    V1
   <num> <int>
1:     1     2
2:     2     2
> options(datatable.optimize=3)        # not ok
> DT[num==1, uniqueN(id), by=group]
   group    V1
   <num> <int>
1:     1     2
2:     1     2
> DT[num==1, sum(num), by=group]       # ok
   group    V1
   <num> <num>
1:     1     7
2:     2     4
> DT[num==1, length(num), by=group]    # not ok
   group    V1
   <num> <int>
1:     1     7
2:     1     4
> options(datatable.optimize=2)        # ok
> DT[num==1, length(num), by=group]
   group    V1
   <num> <int>
1:     1     7
2:     2     4
> 

لماذا انزلقت في الاختبارات؟ لأنه يحدث فقط إذا تم فرز عمود التجميع (انظر الكود أدناه)! لم أتحقق من التجميع في الأعمدة المصنفة على وجه التحديد.

library(data.table)
DT = data.table(
  id = c("a","a","a","b","b","c","c","d","d"),
  group = c(1,1,1,1,1,2,2,2,2),
  group2 = c(1,1,1,1,1,2,2,2,1),
  num = 1)
DT[, uniqueN(id), by=group]          # ok 
# group    V1
# <num> <int>
# 1:     1     2
# 2:     2     2
DT[num==1, uniqueN(id), by=group]    # group column wrong
# group    V1
# <num> <int>
# 1:     1     2
# 2:     1     2
DT[num==1, uniqueN(id), by=group2]    # ok with other group column that is not sorted
# group2 V1
# 1:      1  3
# 2:      2  2

setkey(DT, group2)
DT[num==1, uniqueN(id), by=group2]    # not ok anymore since the group column is sorted now
# group2 V1
# 1:      1  3
# 2:      1  2
هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات