Data.table: Несогласованность для здравомыслия, как data.frame для легкого перехода

Созданный на 21 июн. 2015  ·  32Комментарии  ·  Источник: Rdatatable/data.table

(После краткого обсуждения с Мэттом)

Поведение with=FALSE :

require(data.table)
DT = data.table(x=1:5, y=6:10, z=11:15)

DT[, c("y", "z"), with=FALSE]

В разговоре с коллегами, на встречах или по электронной почте кажется, что восстановление поведения data.frame только для тех случаев, когда j является целочисленным / символьным вектором, может только принести больше здравомыслия (несогласованность торговли).

Проблема в том, что использование data.table вращается вокруг [ , и поэтому пользователи сталкиваются с необходимостью изучать эту разницу довольно рано, а необходимость изучения нового синтаксиса для известной базовой операции не сидеть хорошо. Это также, похоже, не помогает объяснить, как data.table является data.frame с этой базовой операцией.

AFAICT, нет никакого реального использования только символьных / целочисленных векторов в j . Поэтому было бы здорово, если бы with=FALSE не понадобилось и можно было бы разбивать столбцы на подмножества способом data.frame:

DT[, c("y", "z")]
DT[, 2:3]

Также следует восстановить возврат вектора по умолчанию в случае только одного столбца и использования drop=FALSE . Это поможет очень быстро преодолеть базовое использование data.frame, не задаваясь вопросом «почему», и начать изучать фактические основные возможности data.table с расширенными возможностями.

Было бы здорово услышать мысли и от других пользователей.

Это уже возникало раньше (поднято Мэттом): http://r.789695.n4.nabble.com/with-FALSE-td4589266.html, но «оставь как есть» было более или менее ответом.

enhancement internals

Все 32 Комментарий

+1 мм

Мне тоже нравится эта идея. Судя по предыдущим ответам, кажется, что самым большим недостатком может быть несогласованность, поскольку новый пользователь ожидает, что два приведенных ниже подхода вернут один и тот же результат.

DT[,c("colA","colB")] 

colvars = c("colA","colB") 
DT[,colvars]

Есть ли способ вернуть одинаковый результат?

@jrowen спасибо. Да, они оба должны возвращать один и тот же результат (как и data.frame).
Однако придется подумать об этом немного больше.

x <- "z"
DT[, x]

В этом случае это было бы неоднозначно, не правда ли?

Один выход из моей головы заключается в том, чтобы усовершенствованные возможности были задействованы в j , только когда они обернуты .() или list() , но, возможно, это слишком велико. изменение конструкции ...

Хм, теперь я думаю, если бы это только создало больше проблем :-(

Возможно, вы могли бы сделать сообщение об ошибке более понятным и помочь пользователю. Или даже найдите случаи и добавьте «with = FALSE» и сообщите пользователю, что изменение было сделано (например, с установкой имен столбцов «старым» способом). Я использую data.table полтора года и периодически хочу использовать номера столбцов для быстрой интерактивной работы и получаю сообщение об ошибке. Ничего страшного в том, чтобы ввести с = FALSE, но хорошее напоминание было бы желательно. Это также послужит обучению новых пользователей.

Я не знаю. Это может просто затруднить обучение людей. Я согласен с Марком, что добавление обескураживающего предупреждения поможет в этом.

Если вы позволите слишком много внимания этому способу доступа к столбцам, это может оказаться чем-то вроде скользкой дорожки. Вы действительно можете сделать это, не делая этого?

  • разрешение числовых векторов (которые усекаются до floor(j) в data.frames)
  • заставляя DT[int_or_char] соответствовать аналогу data.frame (где он подмножества DT как список)

_Aside: _ Если вы сделаете это, возможно, вы могли бы добавить более быстрый аксессор для j (с точки зрения более короткого кода), аналогично подмножеству списка в моем последнем пункте. Я нахожу with=FALSE неудобным и многословным, и поэтому я использовал обходные пути, такие как [.listof`(DT,int_or_char)` (broken in R 3.2.0 onward) and [.noquote (DT,int_or_char) . Подобная функция позволила бы опытным пользователям новой функциональности обойти предупреждение, предложенное Марком, и написать более четкий и читаемый код (поскольку при просмотре своего кода им не пришлось бы задаваться вопросом, смотрят ли они на data.table- или data.frame-style j ).

_EDIT_: я пытаюсь объяснить, что я имею в виду здесь: http://chat.stackoverflow.com/transcript/message/24012297#24012297

Мне очень нравится автоматическое угадывание with=FALSE , но не drop
восстановление - я не хочу, чтобы этот ужасный вариант воскрес и
мутные воды data.table .

Я согласен с Эдуардом, drop = true - одна из худших частей data.frame. Я думаю, что имеет смысл реализовать with = false, так как это улучшает согласованность и существенно не ухудшает качество таблицы данных, но drop = true просто реализует плохую идею ради согласованности.

отправлено из моего Айфона

22 июня 2015 года в 5:22 утра eduard [email protected] написал:

Мне очень нравится автоматическое угадывание with=FALSE , но не drop
восстановление - я не хочу, чтобы этот ужасный вариант воскрес и
мутные воды data.table .

Вс, 21 июня 2015 г., 10:37 утра franknarf1 [email protected] написал:

Я не знаю. Это может просто затруднить обучение людей. я согласен
с Марком, что добавление обескураживающего предупреждения поможет в этом.

Если вы позволите слишком много внимания этому способу доступа к столбцам, он может
доказать что-то вроде скользкой дорожки. Вы действительно можете сделать это без
делать это?

  • установка drop = TRUE по умолчанию
  • позволяя числовые векторы (которые усекаются до пола (j) в
    data.frames)
  • соответствие DT [int_or_char] аналогу data.frame (где он
    подмножества DT как список)

_Aside: _ Если вы сделаете это, возможно, вы могли бы добавить более быстрый аксессор для j
(с точки зрения более короткого кода), аналогично подмножеству списка в моем последнем
пункт списка. Я нахожу с = FALSE неудобным и многословным, и так поступал
обходные пути вроде [.listof (DT,int_or_char)(broken in R 3.2.0 onward) and [.noquote (DT,int_or_char). A function like this would allow experienced users of the new functionality to sidestep the warning Mark suggested and to write clearer, more readable code (since, on reviewing their code, they wouldn't have to wonder whether they were looking at data.table- or data.frame-stylej ).

-
Ответьте на это письмо напрямую или просмотрите его на GitHub
https://github.com/Rdatatable/data.table/issues/1188#issuecomment -113915592
.

-
Ответьте на это письмо напрямую или просмотрите его на GitHub.

Я думаю, что это противоречит цели изменения, если вы не используете drop=TRUE для этих символьных или целочисленных случаев. При использовании синтаксиса data.table DT[,.(mycol)] , обязательно сохраните drop=FALSE ; Я не думаю, что изменение этого случая могло бы хоть как-то помочь.

@ franknarf1 Я не согласен. drop аргумент актуален только для поиска по одному столбцу, поэтому его отсутствие влияет только на часть случаев, и влияние, которое он оказывает на эти случаи, является одним из единообразных, а не странным, иногда это иногда такое поведение data.frame .

@eantonya Да, я думаю, мы не согласны; извините, если повторяюсь, но я постараюсь уточнить. Я тоже не без ума от поведения data.frame иногда-это-иногда-то, но предпосылка этого предлагаемого улучшения заключается в том, что синтаксис data.frame должен поддерживаться в некоторой ограниченной степени.

В рамках этой ограниченной области (когда j (1) не использует столбцы DT и (2) оценивается как символ или целое число ... или что-то в этом роде), мы должны дать людям то, что они ожидают. Это не похоже на то, что мы с вами собираемся его использовать, так что в этом вреда? И если мы не даем им того, чего они ожидают, зачем вообще давать им уступку? У них еще будут основания жаловаться на непоследовательность. (Я не буду использовать его, потому что хочу иметь возможность читать свой код без мысленных накладных расходов на выяснение, используется ли синтаксис data.frame.)

@ franknarf1, возможно, мне следует уточнить.

В идеале я бы хотел, чтобы синтаксис data.frame в j делал все, что делает синтаксис data.frame, как показано ниже:

DT[, 1:2]
DT[, c("x", "y")]

cols = c("x", "y")
DT[, cols]

все они должны возвращать два столбца data.table.

Однако, как указал @jrowen из старого сообщения, последний случай сложен (для случаев, подобных тому, который я показал в предыдущем сообщении). Если с этим случаем нельзя хорошо позаботиться, я лично не вижу огромного преимущества от реализации этой функции. Я могу представить, как объясняю поведение новичкам (или в разговоре) со слишком большим количеством «если и но» ... и это не помогает.

Итак, было бы здорово выяснить, есть ли способ обойти последний сценарий, не нарушая слишком много вещей. И стоит ли оно того.

Я не очень думаю о присутствии drop = . . И ИМО, это не основная часть этого обсуждения, по крайней мере, до тех пор, пока не станет ясно, что мы собираемся реализовать эту функцию.

Я также полностью осведомлен о случае DT[3:4] vs DF[3:4] , но, похоже, это совсем не проблема ... (на SO, или r-help, или здесь, или data.table-help) AFAICT.

@arunsrinivasan Да, я тоже не вижу пользы от изменения функции. Как вы говорите, похоже, что это усложнит объяснение синтаксиса и повлечет за собой беспорядочный код повсюду (поскольку люди начинают использовать синтаксис data.frame в качестве опоры).

_Назад к моей стороне (упомянутой в вашем последнем предложении) _. Да, я никогда не видел, чтобы кто-нибудь еще жаловался на DT[1:3] vs DF[1:3] , но, возможно, им стоит! На самом деле, если бы у нас была функциональность, упомянутая в этой ветке, чтобы DT[.SDcols=1:3] и DT[.SDcols=c("a","b")] работали так, как подсказывает моя интуиция, это было бы действительно удобно. Здесь это не по теме, потому что это изменение не будет каким-то костылем для людей, которые не хотят изучать синтаксис data.table. Не уверен, что это уже FR ... О, только что нашел: https://github.com/Rdatatable/data.table/issues/1149

@arunsrinivasan На самом деле я не вижу большой проблемы в том, что некоторые случаи не работают. Я вижу это как _guessing_ with=FALSE , и иногда нормально угадывать неправильно. Возможно, вместе с предположением можно напечатать предупреждающее сообщение, подобное предположению melt/dcast make.

@ franknarf1 Я не уверен, что вы имеете в виду - конечно, я бы сам использовал эту функцию - я достаточно часто использую with=FALSE и хотел бы, чтобы вам не приходилось вводить его.

Фреймворк, в котором я вижу это изменение, заключается в улучшении использования data.table для всех, а не в попытке имитировать то, что делает data.frame . С этой точки зрения добавление drop back дезинтегрирует использование для продвинутых пользователей, что я считаю очень незначительной краткосрочной выгодой и долгосрочной потерей для новичков. В то время как предположение with=FALSE - это краткосрочное и долгосрочное улучшение для всех.

@eantonya Моя ошибка. Мне было очень трудно проанализировать использование этой функции в моем коде (на глаз).

Что касается улучшения (исключая мимику), разве DT[.SDcols=1:3] Ричардо не справляется с этим лучше (ссылка выше, проблема 1149)?

Я ничего не имею против этого варианта (и я думаю, что он должен работать независимо от этого), но я бы предпочел набирать DT[, 1:3] так как он меньше печатает.

Что касается того, как угадать - я бы предложил следующее - если какое-либо из имен в j содержит имя столбца или любой из специальных точечных символов ( .SD и т. Д.), Тогда не используйте не догадываюсь. В противном случае попытайтесь оценить выражение во внешней среде - если это удастся и вернет вектор типа character / int / numeric - тогда угадайте with=FALSE . В противном случае вернитесь к тому, что мы делаем сейчас.

Я думаю, что это позаботится о приведенных выше случаях и еще нескольких, о которых я могу подумать прямо сейчас.

Подумайте еще раз - оценивать что-то дважды довольно опасно, поэтому, возможно, нормально жить с результатом оценки, каким бы он ни был (в противном случае возвращайте столбцы для символа / целого / числового и фактического результата).

@eantonya Я не очень знаком с

DT <- data.table(a1=1:2, a2=3:4, a3=5:6)
suff = 2
DT[,mean(get(paste0("a",suff)))] # 3.5

suffy = 3
DT[,plot(get(paste0("a",suff)),get(paste0("a",suffy)))] # plots a2 v a3

больше не будет работать, так как j не находит имен ...?

Если бы был реализован какой-то способ предположений, возможно, его можно было бы превратить в вариант, datatable.guesswith , отключенный по умолчанию, но рекомендуемый для людей, сильно привязанных к синтаксису data.frame.

Хорошо, давайте добавим get в список, который включает .SD и друзей. В каких еще случаях это не сработает? Посмотрим, легко ли классифицировать выражения.

Хорошо, я посмотрю, подумаю ли я или найду еще кого-нибудь. Ничего не приходит на ум, кроме mget (которые я не могу понять, как на самом деле использовать здесь) и eval , например

str  = paste0("a",suff)
expr = parse(text=str)
DT[,eval(expr)]

Замечательные комментарии выше. Я думаю, чтобы попытаться собрать все воедино, нам следует внести следующие изменения. Если я правильно прочитал, думаю (надеюсь!) Это всем понравится и никому не понравится.

  1. проверьте j перед вычислением (как это и было сделано в любом случае). Если это одно число или одна строка, тогда будет использоваться = FALSE. Тогда они будут работать:
    DT [, 1]
    DT [, "someCol"]
    В любом случае они сейчас не делают ничего полезного, поэтому не нарушат существующий код. В обоих случаях будет возвращен один столбец data.table в соответствии с 'with = FALSE' и отбрасыванием 'drop'. Возможный сюрприз, связанный с получением одного столбца data.table (в отличие от data.frame), вряд ли расстроит, тем более что столбец будет печататься красиво (верхние и нижние 5 строк), а не длинный вектор, заполняющий консоль.
  2. если j - одиночный символ, он вернет этот столбец как вектор, как всегда. Однако, если это имя столбца отсутствует, вызовите новую ошибку (в любом случае это не принесет ничего полезного, поэтому новая ошибка не нарушит существующий код).
    DT [, existingCol] # вернуть столбец как вектор, как и раньше
    DT [, missingCol]
    Ошибка: j (второй аргумент внутри [...]) - это единственный символ, который не является именем столбца. В data.table j оценивается в пределах своей области видимости. Если missingCol - это переменная в вызывающей области, которая содержит имена или номера столбцов, добавьте с = FALSE; т.е. DT [, missingCol, with = FALSE]. Это отличие от data.frame является преднамеренным и объясняется в FAQ 1.1. . Это позволяет более продвинутое использование: см. Пример в? Data.table.
  3. если j не содержит символов (например, вызовы c (), : , paste (), paste0 () и только номера столбцов или строки), оцените его и ожидайте, что результатом будет число или вектор символов. Затем установите = FALSE. Тогда они будут работать:
    DT [, c (1:10, 50)]
    DT [, c ("ColA", "ColB")]
    DT [, paste0 ("V", 20:25)]
  4. В противном случае текущее поведение.

Мы всегда можем пойти дальше, в зависимости от того, как пойдет. Мы подождем, пока все, кто прокомментировал до сих пор, подтвердят, прежде чем двигаться дальше (и только тогда после 1.9.6 (наконец) на CRAN!)

Мне кажется, это хорошо. Как всегда, спасибо вам и Аруну за проделанную работу.

Звучит отлично.

Чтобы уменьшить _согласованность_, можно удалить значение по умолчанию для аргумента with или сделать его NULL / logical(0) / NA , что соответствует _guess_. Тогда явное использование with=TRUE все еще сможет переопределить новое предложенное поведение. Таким образом, изменение будет сосредоточено на угадывании аргумента with только если он не указан.

@jangorecki Да

Я тоже поддерживаю пересмотренное предложение.

Вот немного другая точка зрения. Есть места, где я бы очень хотел отправить DT в какой-нибудь старый код, ожидающий DF, и автоматически получить большое улучшение скорости merge () (и, возможно, для других операций, связанных с группировкой). К сожалению, из-за поведения [, отличного от DF, это часто не работает, и иногда я заканчиваю тем, что просто перемещаюсь между DT и DF, чтобы сохранить старый код счастливым.

Одно из простых решений - установить совместимость (c ("on", "off", "?")).

off обеспечивает "родное" поведение DT для тех, кто хочет полностью использовать возможности DT.

on обеспечивает "родное" поведение DF, если операция явно не имеет смысла для DF. Например, я не думаю, что у вас может быть DF [DF,], поэтому что-то вроде этого явно будет вызывать соединение в стиле DT.

Возможно, могут быть другие уровни совместимости, например, почти-DF без дропа.

Поскольку это будет setxxx по ссылке, мы надеемся, что он имеет очень небольшую стоимость производительности.

@ronhylton, ваши комментарии имеют гораздо более широкий охват, чем обсуждаемая тема. Возможно, лучше было бы изолировать его как новый FR. Обсуждаемым обнаружением совместимости j можно управлять, например, путем реализации значения по умолчанию with как getOption("datatable.with") и т. Д.

@ronhylton Согласитесь с Яном - лучше поднимите новый вопрос. Один из вариантов - поместить старый код в пакет, тогда он автоматически переключится на базовый синтаксис при передаче таблицы data.table.

Я заходил в эту ветку 3 раза за последний год или около того, и именно тогда я начал использовать data.table . Каждый раз это было потому, что я забыл о опции with = FALSE . Каждый раз, когда я читал эту ветку, я думал: «Ага, правда, должен это помнить», но почему-то не могу.

data.table - фантастический пакет. Мои 2 цента по теме этой ветки: меня не волнует совместимость / согласованность с data.frame . Если он есть, отлично (1 камень, 2 птицы), но последовательность должна быть не только ради этого, она должна быть там, если функция желательна. И суть в том, что dt[i,j] - это очень, очень _интуитивный_ способ доступа к данным, это в значительной степени стандартная нотация, которая существовала веками (или, по крайней мере, одно столетие). Я считаю, что это имеет значение интуитивно и естественно.

Одна из самых популярных поисковых запросов по запросу «r data.table subset by column and row» - это следующая страница: http://personal.colby.edu/personal/m/mgimond/RIntro/04_Manipulating_data_tables.html , где говорится: «Например, чтобы получить доступ к одному значению ячейки dat в строке 23 и столбце 4, введите dat[23, 4] ", потому что этого ожидают все_.

Это отличное исправление того, что было настоящим камнем преткновения для пользователей соответствующего ответа SO, который в конечном итоге должен быть отредактирован, чтобы отразить изменение.

Ошибка в [.data.table (mba,, i):
j (второй аргумент внутри [...]) - это единственный символ, но имя столбца 'i' не найдено. Возможно, вы имели в виду DT [, .. i] или DT [, i, with = FALSE]. Это отличие от data.frame является преднамеренным и объясняется в FAQ 1.1.

такая досадная ошибка, не позволяющая связать файл, я так плохо кодирую, это меня больше пугает.

Привет.

Я заметил, что из-за этого изменения часть моего старого кода больше не работает.

Например, этот код масштабировал значения, содержащиеся в столбцах, определенных mycols.

mycols <- c("A", "B", "C")
myDT[,scale(mycols)]
or
myDT[paste0("z",mycols) := scale(mycols) ]

Но теперь это не работает.
И следующая строка тоже не работает.
myDT[,scale(..mycols)]
добавление с = FALSE не решает проблему.

Мне нужно сделать что-то вроде этого:
myDT[,scale(.SD), .SDcols=esca ]
myDT[,lapply(.SD[,..esca], scale) ]
myDT[, paste0("z",names(.SD)) := scale(.SD) , .SDcols=mycols]

Есть ли способ лучше?

Привет @skanskan!
Пожалуйста, начните новую проблему и дайте ссылку на эту проблему. Очень сложно отслеживать комментарии в закрытых выпусках. Включите данные для создания myDT и вывода. Я пытался следовать тому, что вы написали, но я не могу без данных, показанных ввода и вывода: http://stackoverflow.com/questions/5963269/how-to-make-a-great-r- воспроизводимый пример
Спасибо, Мэтт

Была ли эта страница полезной?
0 / 5 - 0 рейтинги