У меня есть некоторые данные смешанного типа, которые я хотел бы хранить в какой-то структуре данных 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)))
Но действительно ли это - лучший способ?
Поскольку структура фрейма данных в 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
Другой вариант - преобразовать ваш фрейм данных в матрицу списка режимов - каждый элемент матрицы будет списком. стандартные операции с массивами (применимы нарезки с помощью [
, 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
Попытка впихнуть данные в рамку данных кажется мне халтурой. Гораздо лучше рассматривать каждую строку как отдельный объект, а затем думать о наборе данных как о массиве этих объектов.
Эта функция преобразует строки данных в соответствующий формат. (Это код в стиле 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
Если скомпилировать его как щелчок правой кнопкой мыши, а затем построить проект, компоновщик найдет функции и поместит их в библиотеку.
-121--5044246- Существует два случая, в которых будет выброшено CloneNotSupportedException
:
Cloneable
(при условии, что фактическое клонирование в конечном итоге отложит метод клонирования объекта
). Если класс, записывающий этот метод в implements Cloneable
, этого никогда не произойдет (так как любые подклассы наследуют его соответствующим образом). Клонируемый
. Последний случай не может возникнуть в вашем классе (так как вы вызываете непосредственно метод superclass 'в блоке try
, даже если вызывается из подкласса, вызывающего super.clone ()
), и первый не должен, так как ваш класс явно должен реализовывать Cloneable
.
В основном, вы должны зарегистрировать ошибку наверняка, но в данном конкретном случае это произойдет только в том случае, если вы испортите определение вашего класса. Таким образом, рассматривайте его как проверенную версию StartPointerException
(или подобную) - он никогда не будет выброшен, если ваш код работает.
В других ситуациях необходимо быть готовым к этому - нет гарантии, что данный объект является клонируемым, поэтому при ловле исключения следует предпринять соответствующие действия в зависимости от этого условия (продолжить с существующим объектом, взять альтернативную стратегию клонирования, например сериализовать-десериализовать, вызвать IllegalParameterException
, если метод требует параметр клонируемой и т.д.).
Edit : Хотя в целом я должен отметить, что да, clone ()
действительно трудно реализовать правильно и трудно для вызывающих, чтобы знать, будет ли возвращаемое значение то, что они хотят, вдвойне, когда вы считаете глубокий против мелкого клонов. Часто лучше просто полностью избегать всего этого и использовать другой механизм.
Я бы просто использовал данные в «длинном» формате.
Например.
> 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 для извлечения из них желаемого.
Я бы также использовал строки для данных переменной длины, но как в следующем примере: «c (5,5)» для первой фразы. Для выполнения вычислений необходимо использовать eval (parse (text = ...))
.
Например, среднее
может быть вычислено следующим образом:
sapply (data $ token_lengths, function (str) mean (eval (parse (text = str))))