Как удалить строку из файла data.frame без потери атрибутов
для стартеров: я уже много часов искал эту проблему, поэтому, если ответ должен быть тривиальным, пожалуйста, простите меня...
Что я хочу сделать, это удалить строку (№ 101) из data.frame. Он содержит данные теста и не должен появляться в моих анализах. Моя проблема: всякий раз, когда я подмножаюсь из data.frame, атрибуты (особенно комментарии) теряются.
str(x)
# x has comments for each variable
x <- x[1:100,]
str(x)
# now x has lost all comments
Хорошо документировано, что подмножество отбросит все атрибуты - пока это совершенно ясно. Руководство (например, http://stat.ethz.ch/R-manual/R-devel/library/base/html/Extract.data.frame.html) даже предлагает способ сохранения атрибутов:
## keeping special attributes: use a class with a
## "as.data.frame" and "[" method:
as.data.frame.avector <- as.data.frame.vector
`[.avector` <- function(x,i,...) {
r <- NextMethod("[")
mostattributes(r) <- attributes(x)
r
}
d <- data.frame(i= 0:7, f= gl(2,4),
u= structure(11:18, unit = "kg", class="avector"))
str(d[2:4, -1]) # 'u' keeps its "unit"
Я еще не дошел до R, чтобы понять, что именно происходит здесь. Однако простое выполнение этих строк (кроме последних трех) не изменяет поведение моего подмножества. Использование подмножества команд() с соответствующим вектором (100 раз TRUE + 1 FALSE) дает мне тот же результат. И просто сохранение атрибутов переменной и восстановление ее после подмножества тоже не работает.
# Does not work...
tmp <- attributes(x)
x <- x[1:100,]
attributes(x) <- tmp
Конечно, я мог бы написать все комментарии к вектору (var = > comment), подмножество и записать их с помощью цикла, но это не кажется обоснованным решением. И я совершенно уверен, что буду сталкиваться с наборами данных с другими соответствующими атрибутами в будущих анализах.
Итак, вот мои усилия в stackoverflow, Google и мозговой силе застряли. Я был бы очень признателен, если бы кто-нибудь мог помочь мне с намеком. Спасибо!
Ответы
Ответ 1
Если я правильно вас понимаю, у вас есть данные в файле data.frame, а в столбцах data.frame есть комментарии, связанные с ними. Возможно, что-то вроде следующего?
set.seed(1)
mydf<-data.frame(aa=rpois(100,4),bb=sample(LETTERS[1:5],
100,replace=TRUE))
comment(mydf$aa)<-"Don't drop me!"
comment(mydf$bb)<-"Me either!"
Итак, это даст вам что-то вроде
> str(mydf)
'data.frame': 100 obs. of 2 variables:
$ aa: atomic 3 3 4 7 2 7 7 5 5 1 ...
..- attr(*, "comment")= chr "Don't drop me!"
$ bb: Factor w/ 5 levels "A","B","C","D",..: 4 2 2 5 4 2 1 3 5 3 ...
..- attr(*, "comment")= chr "Me either!"
И когда вы подмножите это, комментарии будут удалены:
> str(mydf[1:2,]) # comment dropped.
'data.frame': 2 obs. of 2 variables:
$ aa: num 3 3
$ bb: Factor w/ 5 levels "A","B","C","D",..: 4 2
Чтобы сохранить комментарии, определите функцию [.avector
, как вы это делали выше (из документации), затем добавьте соответствующие атрибуты класса в каждый из столбцов вашего файла data.frame( EDIT: чтобы сохранить уровни факторов bb
, добавьте "factor"
в класс bb
.):
mydf$aa<-structure(mydf$aa, class="avector")
mydf$bb<-structure(mydf$bb, class=c("avector","factor"))
Чтобы комментарии сохранялись:
> str(mydf[1:2,])
'data.frame': 2 obs. of 2 variables:
$ aa:Class 'avector' atomic [1:2] 3 3
.. ..- attr(*, "comment")= chr "Don't drop me!"
$ bb: Factor w/ 5 levels "A","B","C","D",..: 4 2
..- attr(*, "comment")= chr "Me either!"
EDIT:
Если в вашем файле data.frame есть много столбцов, у которых есть атрибуты, которые вы хотите сохранить, вы можете использовать lapply
( EDITED, чтобы включить исходный класс столбца):
mydf2 <- data.frame( lapply( mydf, function(x) {
structure( x, class = c("avector", class(x) ) )
} ) )
Однако это уменьшает комментарии, связанные с самим файлом data.frame(например, comment(mydf)<-"I'm a data.frame"
), поэтому, если у вас есть, назначьте их новому data.frame:
comment(mydf2)<-comment(mydf)
И тогда у вас есть
> str(mydf2[1:2,])
'data.frame': 2 obs. of 2 variables:
$ aa:Classes 'avector', 'numeric' atomic [1:2] 3 3
.. ..- attr(*, "comment")= chr "Don't drop me!"
$ bb: Factor w/ 5 levels "A","B","C","D",..: 4 2
..- attr(*, "comment")= chr "Me either!"
- attr(*, "comment")= chr "I'm a data.frame"
Ответ 2
Для тех, кто ищет решение "все в одном", основанное на объяснении BenBarnes: Вот оно.
(дайте "вверх" на почту от BenBarnes, если это работает для вас)
# Define the avector-subselection method (from the manual)
as.data.frame.avector <- as.data.frame.vector
`[.avector` <- function(x,i,...) {
r <- NextMethod("[")
mostattributes(r) <- attributes(x)
r
}
# Assign each column in the data.frame the (additional) class avector
# Note that this will "lose" the data.frame attributes, therefore write to a copy
df2 <- data.frame(
lapply(df, function(x) {
structure( x, class = c("avector", class(x) ) )
} )
)
# Finally copy the attribute for the original data.frame if necessary
mostattributes(df2) <- attributes(df)
# Now subselects work without losing attributes :)
df2 <- df2[1:100,]
str(df2)
Хорошая вещь: при присоединении класса ко всему элементу data.frame один раз, subselects никогда больше не беспокоят атрибуты.
Хорошо - иногда я ошеломлен тем, насколько сложно выполнять самые простые операции в R. Но я, конечно же, не узнал о функции "classes", если я только что отметил и удалил случай в SPSS;)
Ответ 3
Это решается пакетом sticky
. (Полное раскрытие: я автор пакета.) Примените sticky()
к вашим векторам, и атрибуты сохраняются с помощью операций подмножества. Например:
> df <- data.frame(
+ sticky = sticky( structure(1:5, comment="sticky attribute") ),
+ nonstick = structure( letters[1:5], comment="non-sticky attribute" )
+ )
>
> comment(df[1:3, "nonstick"])
NULL
> comment(df[1:3, "sticky"])
[1] "sticky attribute"
Это работает для любого атрибута, а не только comment
.
Подробнее см. пакет sticky
: