Лучший способ хранить данные переменной длины в R data.frame?

У меня есть некоторые данные смешанного типа, которые я хотел бы хранить в какой-то структуре данных R. Каждая точка данных имеет ряд фиксированных атрибутов, которые могут быть 1-d числовой, факторы, или символы и также ряд данных переменной длины. Например:

id  phrase                    num_tokens  token_lengths
1   "hello world"             2           5 5
2   "greetings"               1           9
3   "take me to your leader"  4           4 2 2 4 6

Фактические значения не все вычислимы друг от друга, но это - разновидность данных. Операции, которые я собираюсь хотеть сделать, включают подмножество данные на основе булевых функций (например, что-то как nchar(data$phrase) > 10 или lapply(data$token_lengths, length) > 2). Я также хотел бы индексировать и средние значения в части переменной длины индексом. Это не работает, но что-то как: mean(data$token_lengths[1], na.rm=TRUE))

Я нашел, что могу рожок для обуви "token_lengths" в data.frame путем создания этого массивом:

d <- data.frame(id=c(1,2,3), ..., token_lengths=as.array(list(c(5,5), 9, c(4,2,2,4,6)))

Но действительно ли это - лучший способ?

9
задан Nick 24 February 2010 в 17:24
поделиться

5 ответов

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

Альтернативный вариант - хранить данные в виде строки и иметь функцию для их извлечения, или создать отдельную функцию, к которой будут присоединены данные, и извлекать их, используя индексы, хранящиеся в кадре данных.

> ## alternative 1
> tokens <- function(x,i=TRUE) Map(as.numeric,strsplit(x[i],","))
> d <- data.frame(id=c(1,2,3), token_lengths=c("5,5", "9", "4,2,2,4,6"))
> 
> tokens(d$token_lengths)
[[1]]
[1] 5 5

[[2]]
[1] 9

[[3]]
[1] 4 2 2 4 6

> tokens(d$token_lengths,2:3)
[[1]]
[1] 9

[[2]]
[1] 4 2 2 4 6

> 
> ## alternative 2
> retrieve <- local({
+   token_lengths <- list(c(5,5), 9, c(4,2,2,4,6))
+   function(i) token_lengths[i]
+ })
> 
> d <- data.frame(id=c(1,2,3), token_lengths=1:3)
> retrieve(d$token_lengths[2:3])
[[1]]
[1] 9

[[2]]
[1] 4 2 2 4 6
1
ответ дан 4 December 2019 в 15:17
поделиться

Другой вариант - преобразовать ваш фрейм данных в матрицу списка режимов - каждый элемент матрицы будет списком. стандартные операции с массивами (применимы нарезки с помощью [, apply () и т. д.).

> d <- data.frame(id=c(1,2,3), num_tokens=c(2,1,4), token_lengths=as.array(list(c(5,5), 9, c(4,2,2,4,6))))
> m <- as.matrix(d)
> mode(m)
[1] "list"
> m[,"token_lengths"]
[[1]]
[1] 5 5

[[2]]
[1] 9

[[3]]
[1] 4 2 2 4 6

> m[3,]
$id
[1] 3

$num_tokens
[1] 4

$token_lengths
[1] 4 2 2 4 6
4
ответ дан 4 December 2019 в 15:17
поделиться

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

Эта функция преобразует строки данных в соответствующий формат. (Это код в стиле S3; вы можете предпочесть использовать одну из "правильных" объектно-ориентированных систем.)

as.mydata <- function(x)
{
   UseMethod("as.mydata")
}

as.mydata.character <- function(x)
{
   convert <- function(x)
   {
      md <- list()
      md$phrase = x
      spl <- strsplit(x, " ")[[1]]
      md$num_words <- length(spl)
      md$token_lengths <- nchar(spl)
      class(md) <- "mydata"
      md
   }
   lapply(x, convert)
}

Теперь весь ваш набор данных выглядит так

mydataset <- as.mydata(c("hello world", "greetings", "take me to your leader"))

mydataset
[[1]]
$phrase
[1] "hello world"

$num_words
[1] 2

$token_lengths
[1] 5 5

attr(,"class")
[1] "mydata"

[[2]]
$phrase
[1] "greetings"

$num_words
[1] 1

$token_lengths
[1] 9

attr(,"class")
[1] "mydata"

[[3]]
$phrase
[1] "take me to your leader"

$num_words
[1] 5

$token_lengths
[1] 4 2 2 4 6

attr(,"class")
[1] "mydata"

Вы можете определить метод print, чтобы сделать это более красивым.

print.mydata <- function(x)
{
   cat(x$phrase, "consists of", x$num_words, "words, with", paste(x$token_lengths, collapse=", "), "letters.")
}
mydataset
[[1]]
hello world consists of 2 words, with 5, 5 letters.
[[2]]
greetings consists of 1 words, with 9 letters.
[[3]]
take me to your leader consists of 5 words, with 4, 2, 2, 4, 6 letters.

Примеры операций, которые вы хотели выполнить, довольно просты с данными в этом формате.

sapply(mydataset, function(x) nchar(x$phrase) > 10)
[1]  TRUE FALSE  TRUE
4
ответ дан 4 December 2019 в 15:17
поделиться

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

-121--5044246-

Существует два случая, в которых будет выброшено CloneNotSupportedException :

  1. Клонируемый класс не реализован Cloneable (при условии, что фактическое клонирование в конечном итоге отложит метод клонирования объекта ). Если класс, записывающий этот метод в implements Cloneable , этого никогда не произойдет (так как любые подклассы наследуют его соответствующим образом).
  2. Исключение явно вызывается реализацией - это рекомендуемый способ предотвратить клонирование в подклассе, когда суперкласс имеет значение Клонируемый .

Последний случай не может возникнуть в вашем классе (так как вы вызываете непосредственно метод superclass 'в блоке try , даже если вызывается из подкласса, вызывающего super.clone () ), и первый не должен, так как ваш класс явно должен реализовывать Cloneable .

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


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

Edit : Хотя в целом я должен отметить, что да, clone () действительно трудно реализовать правильно и трудно для вызывающих, чтобы знать, будет ли возвращаемое значение то, что они хотят, вдвойне, когда вы считаете глубокий против мелкого клонов. Часто лучше просто полностью избегать всего этого и использовать другой механизм.

-121--709712-

Я бы просто использовал данные в «длинном» формате.

Например.

> d1 <- data.frame(id=1:3, num_words=c(2,1,4), phrase=c("hello world", "greetings", "take me to your leader"))
> d2 <- data.frame(id=c(rep(1,2), rep(2,1), rep(3,5)), token_length=c(5,5,9,4,2,2,4,6))
> d2$tokenid <- with(d2, ave(token_length, id, FUN=seq_along))
> d <- merge(d1,d2)
> subset(d, nchar(phrase) > 10)
  id num_words                 phrase token_length tokenid
1  1         2            hello world            5       1
2  1         2            hello world            5       2
4  3         4 take me to your leader            4       1
5  3         4 take me to your leader            2       2
6  3         4 take me to your leader            2       3
7  3         4 take me to your leader            4       4
8  3         4 take me to your leader            6       5
> with(d, tapply(token_length, id, mean))
  1   2   3 
5.0 9.0 3.6 

Как только данные находятся в длинном формате, можно использовать sqldf или plyr для извлечения из них желаемого.

4
ответ дан 4 December 2019 в 15:17
поделиться

Я бы также использовал строки для данных переменной длины, но как в следующем примере: «c (5,5)» для первой фразы. Для выполнения вычислений необходимо использовать eval (parse (text = ...)) .

Например, среднее может быть вычислено следующим образом:

sapply (data $ token_lengths, function (str) mean (eval (parse (text = str))))

0
ответ дан 4 December 2019 в 15:17
поделиться
Другие вопросы по тегам:

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