Создайте пустые данные.рамка



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



лучшее, что я смог сделать до сих пор что-то вроде:



df <- data.frame(Date=as.Date("01/01/2000", format="%m/%d/%Y"), 
File="", User="", stringsAsFactors=FALSE)
df <- df[-1,]


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



есть ли лучший способ сделать это?

688   13  

13 ответов:

просто инициализируйте его пустыми векторами:

df <- data.frame(Date=as.Date(character()),
                 File=character(), 
                 User=character(), 
                 stringsAsFactors=FALSE) 

вот другой пример с различными типами столбцов:

df <- data.frame(Doubles=double(),
                 Ints=integer(),
                 Factors=factor(),
                 Logicals=logical(),
                 Characters=character(),
                 stringsAsFactors=FALSE)

str(df)
> str(df)
'data.frame':   0 obs. of  5 variables:
 $ Doubles   : num 
 $ Ints      : int 
 $ Factors   : Factor w/ 0 levels: 
 $ Logicals  : logi 
 $ Characters: chr 

N. B.:

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

если вы уже есть существующий фрейм данных скажем df, которая имеет столбцы, которые вы хотите, то вы можете просто создать пустой фрейм данных, удалив все строки:

empty_df = df[FALSE,]

обратите внимание, что df все еще содержит данные, но empty_df - нет.

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

вы можете сделать это без указания типа столбца

df = data.frame(matrix(vector(), 0, 3,
                dimnames=list(c(), c("Date", "File", "User"))),
                stringsAsFactors=F)

вы могли бы использовать read.table С пустой строкой для ввода text следующим образом:

colClasses = c("Date", "character", "character")
col.names = c("Date", "File", "User")

df <- read.table(text = "",
                 colClasses = colClasses,
                 col.names = col.names)

альтернативно задание col.names как строку:

df <- read.csv(text="Date,File,User", colClasses = colClasses)

спасибо Ричарду Скривену за улучшение

самый эффективный способ сделать это-использовать structure создать список, который имеет класс "data.frame":

structure(list(Date = as.Date(character()), File = character(), User = character()), 
          class = "data.frame")
# [1] Date File User
# <0 rows> (or 0-length row.names)

чтобы поставить это в перспективе по сравнению с принятым в настоящее время ответом, вот простой тест:

s <- function() structure(list(Date = as.Date(character()), 
                               File = character(), 
                               User = character()), 
                          class = "data.frame")
d <- function() data.frame(Date = as.Date(character()),
                           File = character(), 
                           User = character(), 
                           stringsAsFactors = FALSE) 
library("microbenchmark")
microbenchmark(s(), d())
# Unit: microseconds
#  expr     min       lq     mean   median      uq      max neval
#   s()  58.503  66.5860  90.7682  82.1735 101.803  469.560   100
#   d() 370.644 382.5755 523.3397 420.1025 604.654 1565.711   100

Если вы ищете для краткости :

read.csv(text="col1,col2")

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

Я создал пустой фрейм данных, используя следующий код

df = data.frame(id = numeric(0), jobs = numeric(0));

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

newrow = c(3, 4)
df <- rbind(df, newrow)

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

  X3 X4
1  3  4

решение этой проблемы заключается в преобразовании newrow в тип df следующим образом

newrow = data.frame(id=3, jobs=4)
df <- rbind(df, newrow)

теперь дает правильный фрейм данных при отображении с именами столбцов следующим образом

  id nobs
1  3   4 

просто объявить

table = data.frame()

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

Если вы хотите создать пустые данные.рамка с динамическими именами (colnames в переменной), это может помочь:

names <- c("v","u","w")
df <- data.frame()
for (k in names) df[[k]]<-as.numeric()

вы также можете изменить типы, если вам это нужно. например:

names <- c("u", "v")
df <- data.frame()
df[[names[1]]] <- as.numeric()
df[[names[2]]] <- as.character()

если вы хотите объявить такое data.frame С большим количеством столбцов, это, вероятно, будет боль, чтобы ввести все классы столбцов вручную. Особенно если вы можете использовать rep, этот подход прост и быстр (примерно на 15% быстрее, чем другое решение, которое можно обобщить следующим образом):

если нужные классы столбцов находятся в векторе colClasses, вы можете сделать следующее:

library(data.table)
setnames(setDF(lapply(colClasses, function(x) eval(call(x)))), col.names)

lapply приведет к списку нужной длины, каждый элемент которого является просто пустой типизированный вектор типа numeric() или integer().

setDF преобразует этот list со ссылкой на data.frame.

setnames добавляет нужные имена по ссылке.

скорость сравнения:

classes <- c("character", "numeric", "factor",
             "integer", "logical","raw", "complex")

NN <- 300
colClasses <- sample(classes, NN, replace = TRUE)
col.names <- paste0("V", 1:NN)

setDF(lapply(colClasses, function(x) eval(call(x))))

library(microbenchmark)
microbenchmark(times = 1000,
               read = read.table(text = "", colClasses = colClasses,
                                 col.names = col.names),
               DT = setnames(setDF(lapply(colClasses, function(x)
                 eval(call(x)))), col.names))
# Unit: milliseconds
#  expr      min       lq     mean   median       uq      max neval cld
#  read 2.598226 2.707445 3.247340 2.747835 2.800134 22.46545  1000   b
#    DT 2.257448 2.357754 2.895453 2.401408 2.453778 17.20883  1000  a 

это также быстрее, чем при использовании structure подобным образом:

microbenchmark(times = 1000,
               DT = setnames(setDF(lapply(colClasses, function(x)
                 eval(call(x)))), col.names),
               struct = eval(parse(text=paste0(
                 "structure(list(", 
                 paste(paste0(col.names, "=", 
                              colClasses, "()"), collapse = ","),
                 "), class = \"data.frame\")"))))
#Unit: milliseconds
#   expr      min       lq     mean   median       uq       max neval cld
#     DT 2.068121 2.167180 2.821868 2.211214 2.268569 143.70901  1000  a 
# struct 2.613944 2.723053 3.177748 2.767746 2.831422  21.44862  1000   b

Если вы не возражаете не указывать типы данных явно, вы можете сделать это следующим образом:

headers<-c("Date","File","User")
df <- as.data.frame(matrix(,ncol=3,nrow=0))
names(df)<-headers

#then bind incoming data frame with col types to set data types
df<-rbind(df, new_df)

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

create_empty_table <- function(num_rows, num_cols) {
    frame <- data.frame(matrix(NA, nrow = num_rows, ncol = num_cols))
    return(frame)
}

чтобы создать пустой кадр при указании класса каждого столбца, просто передайте вектор нужных типов данных в следующую функцию:

create_empty_table <- function(num_rows, num_cols, type_vec) {
  frame <- data.frame(matrix(NA, nrow = num_rows, ncol = num_cols))
  for(i in 1:ncol(frame)) {
    print(type_vec[i])
    if(type_vec[i] == 'numeric') {frame[,i] <- as.numeric(df[,i])}
    if(type_vec[i] == 'character') {frame[,i] <- as.character(df[,i])}
    if(type_vec[i] == 'logical') {frame[,i] <- as.logical(df[,i])}
    if(type_vec[i] == 'factor') {frame[,i] <- as.factor(df[,i])}
  }
  return(frame)
}

использовать следующим образом:

df <- create_empty_table(3, 3, c('character','logical','numeric'))

что дает:

   X1  X2 X3
1 <NA> NA NA
2 <NA> NA NA
3 <NA> NA NA

, чтобы подтвердить свой выбор, выполните следующее:

lapply(df, class)

#output
$X1
[1] "character"

$X2
[1] "logical"

$X3
[1] "numeric"

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

nms <- sample(LETTERS,sample(1:10))
as.data.frame(t(matrix(nrow=length(nms),ncol=0,dimnames=list(nms))))

Comments

    Ничего не найдено.