Как правильно использовать списки в R?

Небольшое обновление:

  • Всегда всегда используйте опцию knitr chunk results='asis', как кто-то указал в предыдущем комментарии.
  • Можно создавать сводки, включая графики png , используя print():

    print(dfSummary(iris), method = "render")

  • Начиная с версии 0.9.0 (доступно только на GitHub по состоянию на февраль 2019 г.), сводки уценки также будут включать png ] при условии, что вы указываете следующие аргументы:

    • plain.ascii = FALSE
    • style = "grid"
    • физическое местоположение для временного png ] (tmp.img.dir)

      dfSummary(iris, plain.ascii = FALSE, style = "grid", tmp.img.dir = "/tmp")

Дополнительные советы

    [ 1126] В обоих случаях вам (по всей вероятности) потребуется отрегулировать размер графиков с помощью параметра dfSummary() graph.magnif (попробуйте значения между .75 и .85).
  • Исключите столбец или два, чтобы избежать слишком широких сводок:
    dfSummary(iris, [...], varnumbers = FALSE, valid.col = FALSE)

308
задан Gregor 5 October 2017 в 05:03
поделиться

7 ответов

Просто для решения последней части вашего вопроса, поскольку это действительно указывает на разницу между списком и вектор в R:

Почему эти два выражения не возвращают один и тот же результат?

X = список (1, 2, 3, 4); X2 = список (1: 4)

список может содержать любой другой класс в качестве каждого элемента. Таким образом, вы можете иметь список, где первый элемент - это вектор символов, второй - это кадр данных и т. Д. В этом случае вы создали два разных списка. X имеет четыре векторы, каждая из длин 1. x2 имеет 1 вектор длины 4:

> length(x[[1]])
[1] 1
> length(x2[[1]])
[1] 4

, поэтому они совершенно разные списки.

rные списки очень похоже на ASH-карту . Структура данных в том, что каждое значение индекса может быть связано с любым объектом. Вот простой пример списка, который содержит 3 разных класса (включая функцию):

> complicated.list <- list("a"=1:4, "b"=1:3, "c"=matrix(1:4, nrow=2), "d"=search)
> lapply(complicated.list, class)
$a
[1] "integer"
$b
[1] "integer"
$c
[1] "matrix"
$d
[1] "function"

, учитывая, что последний элемент - это функция поиска, я могу назвать это так:

> complicated.list[["d"]]()
[1] ".GlobalEnv" ...

в качестве окончательного комментария к этому: Отметить, что данные. Сделайте data.rame действительно список (из Data.rame Документация):

Кадр данных представляет собой список переменных одинакового количества строк с Уникальные имена строк, данный класс «Data.Frame»

Вот почему столбцы в данных. Crame могут иметь разные типы данных, а столбцы в матрице не могут. В качестве примера здесь я пытаюсь создать матрицу с номерами и персонажами:

> a <- 1:4
> class(a)
[1] "integer"
> b <- c("a","b","c","d")
> d <- cbind(a, b)
> d
 a   b  
[1,] "1" "a"
[2,] "2" "b"
[3,] "3" "c"
[4,] "4" "d"
> class(d[,1])
[1] "character"

Обратите внимание, как я не могу изменить тип данных в первом столбце к числовым, потому что второй столбец имеет символы:

> d[,1] <- as.numeric(d[,1])
> class(d[,1])
[1] "character"
143
ответ дан 23 November 2019 в 01:18
поделиться

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

Несмотря на то, что принятые ответы предлагают, list, объекты в R не карты хеша. Если Вы хотите сделать параллель с Python, list больше похожи, Вы предполагаете, Python list с (или tuple с на самом деле).

лучше описать, как большинство объектов R хранится внутренне (тип C объекта R SEXP). Они сделаны в основном трех частей:

  • заголовок, который объявляет тип R объекта, длины и некоторых других метаданных;
  • часть данных, которая является стандартом C выделенный "куче" массив (непрерывный блок памяти);
  • атрибуты, которые являются именованным связанным списком указателей на другие объекты R (или NULL, если объект не имеет атрибутов).

С внутренней точки зрения, существует мало различия между list и numeric вектор, например. Значения, которые они хранят, просто отличаются. Давайте повредим два объекта в парадигму, которую мы описали прежде:

x <- runif(10)
y <- list(runif(10), runif(3))

Для [1 112]:

  • в заголовке будет сказано, что тип numeric (REALSXP в C-стороне), длина равняется 10 и другому материалу.
  • часть данных будет массивом, содержащим 10 double значения.
  • атрибуты NULL, так как объект не имеет никого.

Для [1 117]:

  • в заголовке будет сказано, что тип list (VECSXP в C-стороне), длина равняется 2 и другому материалу.
  • часть данных будет массивом, содержащим 2 указателя на два типа SEXP, указывая на значение, полученное [1 120] и runif(3) соответственно.
  • атрибуты NULL, что касается [1 123].

Так единственная разница между numeric вектор и list - то, что numeric часть данных сделана из [1 127] значения, в то время как для list часть данных является массивом указателей на другие объекты R.

, Что происходит с именами? Ну, имена являются просто некоторыми атрибутами, которые можно присвоить объекту. Давайте посмотрим объект ниже:

z <- list(a=1:3, b=LETTERS)
  • в заголовке будет сказано, что тип list (VECSXP в C-стороне), длина равняется 2 и другому материалу.
  • часть данных будет массивом, содержащим 2 указателя на два типа SEXP, указывая на значение, полученное [1 131] и LETTERS соответственно.
  • атрибуты теперь присутствуют и names компонент, который является character объект R со значением c("a","b").

От уровня R, можно получить атрибуты объекта с эти attributes функция.

значение ключа, типичное для карты хеша в R, является просто иллюзией. Когда Вы говорите:

z[["a"]]

это - то, что происходит:

  • [[ функция подмножества вызвана;
  • аргумент функции ("a") имеет тип character, таким образом, метод проинструктирован для поиска такого значения от эти names атрибут (если есть) объекта z;
  • , если эти names атрибут не там, NULL, возвращается;
  • , если существующий, эти "a" значение ищется в нем. Если "a" не название объекта, NULL возвращается;
  • , если существующий, положение определяется (1 в примере). Таким образом, первый элемент списка возвращается, т.е. эквивалент [1 147].

поиск значения ключа является довольно косвенным и является всегда позиционным. Кроме того, полезный для учета:

  • в хеше отображает единственный предел, который должен иметь ключ, то, что это должно быть hashable. names в R должны быть строки (character векторы);
  • в картах хеша у Вас не может быть двух идентичных ключей. В R можно присвоиться names к объекту с повторными значениями. Например:

    names(y) <- c("same", "same")
    

    совершенно допустимо в R. Когда Вы пробуете y[["same"]], первое значение получено. Необходимо знать почему в этой точке.

В заключение способность дать произвольные атрибуты объекту дает Вам появление чего-то другого с внешней точки зрения. Но R list с не являются картами хеша всегда.

2
ответ дан 23 November 2019 в 01:18
поделиться

Просто для того, чтобы принять подброс ваших вопросов:

Эта статья на индексации рассматривает вопрос о разнице между [] и [[.

Короче [[]] выбирает один элемент из списка, и [] возвращает список выбранных элементов. В вашем примере X = список (1, 2, 3, 4) ' элемент 1 представляет собой одно целое число, но x [[[]] возвращает один 1 и x [1] Возвращает список только с одним значением.

> x = list(1, 2, 3, 4)
> x[1]
[[1]]
[1] 1

> x[[1]]
[1] 1
34
ответ дан 23 November 2019 в 01:18
поделиться

Одной из причин. Списки работы, как они делают (упорядоченные) - это устранение необходимости упорядоченного контейнера, которое может содержать любой тип на любом узле, которые векторы не делают. Списки повторно используются для различных целей в R, в том числе формируя основание данных. Crame , который представляет собой список векторов произвольного типа (но одинаковой длины).

Почему эти два выражения не возвращают один и тот же результат?

x = list(1, 2, 3, 4); x2 = list(1:4)

Чтобы добавить к ответу @ Shane, если вы хотите получить тот же результат, попробуйте:

x3 = as.list(1:4)

, который принудительный вектор 1: 4 в список.

13
ответ дан 23 November 2019 в 01:18
поделиться

Что касается Ваших вопросов, то позвольте мне обратиться к ним по порядку и привести несколько примеров:

1). Возвращается список, если и когда заявление о возвращении добавляет его. Рассмотрим

 R> retList <- function() return(list(1,2,3,4)); class(retList())
 [1] "list"
 R> notList <- function() return(c(1,2,3,4)); class(notList())
 [1] "numeric"
 R> 

2 ). Имена просто не установлены:

R> retList <- function() return(list(1,2,3,4)); names(retList())
NULL
R> 

3). Они не возвращают то же самое. Ваш пример дает

R> x <- list(1,2,3,4)
R> x[1]
[[1]]
[1] 1
R> x[[1]]
[1] 1

, где x[1] возвращает первый элемент x -- который совпадает с x. Каждый скаляр является вектором длины один. С другой стороны x[[1]] возвращает первый элемент списка.

4) Наконец, эти два элемента отличаются друг от друга тем, что создают соответственно список, содержащий четыре скаляра, и список с одним элементом (который является вектором из четырех элементов).

62
ответ дан 23 November 2019 в 01:18
поделиться

Боюсь, это не сработает, поскольку объявленные вами два лямбда-выражения (и делегаты) фактически являются разными объектами и возвращают разные ссылки. Следовательно, удаление обработчика ( - = ) всегда будет неуспешным.

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

-121--1019982-

Существует два метода реализации службы отображения, подобных описанному вами.

  1. Клиенты отправляют глобально уникальные идентификаторы, или
  2. Сервер генерирует глобально уникальные идентификаторы

Клиенты отправляют глобально уникальные идентификаторы

Насколько мне известно, 1. следует пытаться только с помощью Guid , если только вы не разработаете аналогичное средство для передачи достаточно четкой информации в короткий поток байтов. В любом случае, если у вас есть поток байтов, которые представляют глобально уникальный идентификатор, вы можете сделать что-то подобное

// source is either a Guid, or some other globally unique byte stream
byte[] bytes = Guid.NewGuid ().ToByteArray ();
string base64String = Convert.ToBase64String (bytes).Trim ("=");

, чтобы получить считываемую пользователем последовательность алфавитно-цифровых чисел, которая выглядит случайной, но избегает конфликтов, присущих другим случайным схемам. Guid содержит 16 байт или 128 бит, что соответствует приблизительно 19 символам для полной кодировки Base64.

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

Если вы действительно идете по этому маршруту, рассмотрите глобально уникальные потоки байтов Google. О, и ДЕРЖИТЕСЬ ПОДАЛЬШЕ ОТ СЛУЧАЙНЫХ БАЙТОВ , иначе вам придется построить разрешение коллизий ПОВЕРХ вашего крошечного генератора URI.

Сервер генерирует глобальные уникальные идентификаторы

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

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

Предполагая желаемую длину 5 символов, и допустим, вы идете с Base64 кодировкой, каждый идентификатор может представлять до 5 символов на 7 бит на символ равно 35 бит или 2 ^ 35 [34 359 738 368] различных значений. Это довольно большой домен. *

Тогда возникает вопрос о возврате значения для данного представления. Вероятно, есть много способов сделать это, но я бы пошел с чем-то вроде этого,

  • Перечислить все возможные значения в «списке свободных значений» в базе данных
  • Удалить значение из списка свободных значений при использовании
  • Добавить значение в список свободных значений при выпуске

Усовершенствования или оптимизации могут включать

  • Не перечислять все значения в диапазоне [0, 2 ^ 35], вместо перечисления управляемого подмножества, скажем, 100 000 значений одновременно, и когда все значения израсходованы, просто создайте еще 100 000 значений в последовательности и продолжайте
  • Добавьте дату истечения срока к значениям, и повторно использовать просроченные значения в конце дня
  • Распределите ваш сервис, когда параллелизация вашего сервиса просто распределяет небольшие взаимоисключающие подмножества вашего списка бесплатных услуг

Вывод

Итог: вы хотите гарантировать уникальность - так что коллизии являются большим нет-нет.


* = 34 359 738 368 - размер необработанного домена, это все идентификаторы от 0 длины до 5 длины. Если вы заинтересованы в ограничении всех идентификаторов минимальной и максимальной длиной 5, то ваш домен выглядит так, что все идентификаторы длиной от 0 до 5 (2 ^ 35) меньше, чем все идентификаторы длиной от 0 до 4 (2 ^ 28) составляет от 2 ^ 35 до 2 ^ 28 = 34 091 302 912, что все еще довольно велико:)

-121--432â6-

Вы говорите:

Для другого можно вернуть списки из функций, даже если вы никогда передан в списке при вызове функция и даже несмотря на то, что функция не содержит конструктор List, Например,

x = strsplit(LETTERS[1:10], "") # passing in an object of type 'character'
class(x)
# => 'list'

И я полагаю, вы предполагаете, что это проблема (?). Я здесь, чтобы сказать вам, почему это не проблема: -). Ваш пример немного прост, так как при разделении строки имеется список с элементами длиной 1 элемента, поэтому известно, что x [[1]] совпадает с unlist (x) [1] . Но что, если результат strsplit вернул результаты различной длины в каждой ячейке. Просто вернуть вектор (против списка) совсем не получится.

Например:

stuff <- c("You, me, and dupree",  "You me, and dupree",
           "He ran away, but not very far, and not very fast")
x <- strsplit(stuff, ",")
xx <- unlist(strsplit(stuff, ","))

В первом случае ( x : который возвращает список) можно указать, какой была 2-я «часть» 3-й строки, например: x [[3]] [2] . Как вы могли бы сделать то же самое с помощью xx теперь, когда результаты были «распутаны» ( unlist -ed)?

9
ответ дан 23 November 2019 в 01:18
поделиться

Просто добавлю еще один момент:

R действительно имеет структуру данных, эквивалентную Python dict в хэш пакет . Вы можете прочитать об этом в этом сообщении в блоге группы Open Data . Вот простой пример:

> library(hash)
> h <- hash( keys=c('foo','bar','baz'), values=1:3 )
> h[c('foo','bar')]
<hash> containing 2 key-value pairs.
  bar : 2
  foo : 1

С точки зрения удобства использования хэш-класс очень похож на список. Но производительность лучше для больших наборов данных.

11
ответ дан 23 November 2019 в 01:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: