Создайте пустые данные.рамка
Я пытаюсь инициализировать данные.рамка без каких-либо строк. В принципе, я хочу указать типы данных для каждого столбца и назвать их, но не иметь никаких строк, созданных в результате.
лучшее, что я смог сделать до сих пор что-то вроде:
df <- data.frame(Date=as.Date("01/01/2000", format="%m/%d/%Y"),
File="", User="", stringsAsFactors=FALSE)
df <- df[-1,]
который создает данные.фрейм с одной строкой, содержащей все типы данных и имена столбцов, которые я хотел, но также создает бесполезную строку, которую затем необходимо удалить.
есть ли лучший способ сделать это?
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: chrN. 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
Если вы хотите создать пустые данные.рамка с динамическими именами (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