빈 데이터 프레임 만들기


480

행없이 data.frame을 초기화하려고합니다. 기본적으로 각 열의 데이터 형식을 지정하고 이름을 지정하지만 결과적으로 행이 생성되지 않습니다.

내가 지금까지 할 수 있었던 최선은 다음과 같습니다.

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

원하는 모든 데이터 유형과 열 이름을 포함하는 단일 행으로 data.frame을 생성하지만 쓸모없는 행을 생성하여 제거해야합니다.

더 좋은 방법이 있습니까?

답변:


652

빈 벡터로 초기화하십시오.

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 

NB :

data.frame잘못된 유형의 빈 열로 초기화하면 다른 유형의 열이있는 행을 더 이상 추가 할 수 없습니다.
이 방법은 처음부터 올바른 열 유형을 가질 것이라는 점에서 조금 더 안전 합니다. 따라서 코드가 일부 열 유형 검사에 의존하는 data.frame경우 행이 0 인 경우에도 작동 합니다.


3
모든 필드를 NULL로 초기화하면 동일합니까?
yosukesabai

8
@yosukesabai : 아니오, NULL로 열을 초기화하면 열이 추가되지 않습니다 :)
digEmAll

6
@yosukesabai : data.frame의 열을 입력 했으므로 예, 초기화 data.frame하려면 열의 유형을 결정해야합니다 ...
digEmAll

1
@jxramos : 글쎄, 실제로 data.frame열 유형의 " 우선 순위 "에 대해 제한적이지는 않습니다 (예를 들어, 날짜 열 또는 요소 목록을 포함하는 열을 추가 할 수 있음). 또한이 질문은 절대 참조가 아닙니다. 예를 들어 올바른 유형의 열을 지정하지 않으면 다른 유형의 열이있는 행 추가를 차단하지 않으므로 메모를 추가하지만 모든 가능성을 다루지 않기 때문에 모든 기본 유형의 예제 ...
digEmAll

3
@ user4050 : 빈 data.frame을 만드는 것에 대한 질문이었습니다. 따라서 행 수가 0 일 때 ... 아마도 NA에 가득 찬 data.frame(Doubles=rep(as.double(NA),numberOfRow), Ints=rep(as.integer(NA),numberOfRow))
data.frame

140

이미 존재하는 데이터 프레임이있는 경우 df원하는 열이 있다고 가정 하면 모든 행을 제거하여 빈 데이터 프레임을 만들 수 있습니다.

empty_df = df[FALSE,]

공지 df여전히 데이터를 포함하지만, empty_df하지 않습니다.

빈 행으로 새 인스턴스를 만드는 방법을 찾고있는이 질문을 찾았으므로 일부 사람들에게 도움이 될 것이라고 생각합니다.


2
멋진 생각입니다. 행을 제외한 모든 열을 유지하십시오. 공감 한 사람은 무언가를 놓쳤다.
Ram Narasimhan 2016 년

1
좋은 해결책이지만 0 행의 데이터 프레임이 있음을 알았습니다. 데이터 프레임의 크기를 동일하게 유지하려면 new_df = df [NA,]를 제안합니다. 또한 이전 열을 새 데이터 프레임에 저장할 수 있습니다. 예를 들어, 원본 df에서 "날짜"열을 얻으려면 (나머지 NA는 유지) : new_df $ Date <-df $ Date.
Katya

2
@ Katya, df[NA,]이렇게하면 인덱스에도 영향을 미칩니다 (원하는 것은 아닐 것입니다). 대신 df[TRUE,] = NA; 그러나 원본을 덮어 씁니다. 먼저 dataframe을 복사해야합니다 copy_df = data.frame(df)다음copy_df[TRUE,] = NA
toto_tico

3
@Katya, 또는 당신은 또한 쉽게에 빈 행을 추가 할 수 있습니다 empty_dfempty_df[0:nrow(df),] <- NA.
toto_tico

1
@ Katya에서는 코드로 표시하려는 항목 주위에 역 인용 부호 (`)를 사용하고 *를 사용하여 기울임 꼴로 표시 하고 **를 사용하여 굵게 표시 하는 다른 항목이 있습니다. SOMarkdown Syntax를 모두 읽고 싶을 것입니다 . 대부분의 경우 답변에 대해서만 의미가 있습니다.
toto_tico

79

열 유형을 지정하지 않고도 할 수 있습니다

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

4
이 경우 열 유형은 기본적으로 vector () 당 논리로 설정되지만 df에 추가 된 요소 유형으로 재정의됩니다. 'X'- [1,1] <STR (DF), DF 시도
데이브 X

58

다음과 같이 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)

개선을위한 Richard Scriven에게 감사합니다


4
또는 read.table(text = "", ...)명시 적으로 연결을 열 필요가 없습니다.
Rich Scriven

멋진. 아마도 많은 잠재적 인 컬럼에 대해 이것을 수행하는 가장 확장 가능하고 자동화 된 방법
MichaelChirico 1

3
read.csv접근법은에서와 readr::read_csv같이 작동합니다 read_csv("Date,File,User\n", col_types = "Dcc"). 이 방법으로 필요한 구조의 빈 티블을 직접 만들 수 있습니다.
Heather Turner

27

가장 효율적인 방법 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

data.table은 일반적으로 함수 .internal.selfref를 호출하지 않고는 속일 수없는 속성을 포함 data.table합니다. 여기에 문서화되지 않은 행동에 의존하지 않습니까?
Adam Ryczkowski

@AdamRyczkowski 기본 "data.frame"클래스와 data.table 패키지 의 추가 기능 "data.table"클래스를 혼동하고 있다고 생각합니다 .
토마스

예. 명확히. 내 잘못이야. 마지막 코멘트는 무시하십시오. 검색 할 때이 스레드를 data.table발견하고 Google이 내가 원하는 것을 찾았으며 여기의 모든 것이 data.table관련 되어 있다고 가정했습니다 .
Adam Ryczkowski

1
@PatrickT 코드가하는 일이 의미가 있는지 확인하는 것은 없습니다. data.frame()이름, 행 이름 등에 대한 점검을 제공합니다.
Thomas

26

그냥 선언

table = data.frame()

rbind첫 줄 을 시도 하면 열이 만들어집니다.


2
"각 열에 대한 데이터 유형을 지정하고 이름을 지정하고 싶습니다"라는 OP의 요구 사항을 실제로 충족하지 않습니다. 경우 다음 단계는이 rbind되지 않을 경우이 ..., 잘 작동
그레고르 토마스

어쨌든이 간단한 솔루션에 감사드립니다. 열이 두 data.frame 사이에 해당하는 경우에만 rbind를 사용할 수 있다고 생각했기 때문에 특정 열로 data.frame을 초기화하고 싶었습니다. 그렇지 않은 것 같습니다. rbind를 사용할 때 단순히 data.frame을 초기화 할 수 있다는 것에 놀랐습니다. 감사.
giordano

4
여기에 가장 제안 된 솔루션입니다. 나를 위해 제안 된 방법을 사용하여 완벽하게 작업했습니다 rbind().
Kots

17

부족함을 찾고 있다면 :

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

따라서 열 이름을 별도로 지정할 필요가 없습니다. 데이터 프레임을 채울 때까지 기본 열 유형이 논리적으로 표시됩니다.


read.csv는 텍스트 인수를 구문 분석하여 열 이름을 얻습니다. read.table (text = "", col.names = c ( "col1", "col2"))보다 작습니다.
marc

나는 얻는다 :Error in data.frame(..., check.names = FALSE) : arguments imply differing number of rows: 0, 2
Climbs_lika_Spyder 21:29에

OP의 요구 사항 인 "각 열에 대한 데이터 유형을 지정하고 싶습니다"를 충족시키지 못하지만 수정 될 수 있습니다.
Gregor Thomas

14

다음 코드를 사용하여 빈 데이터 프레임을 만들었습니다.

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 

7

빈 데이터 프레임만들려면 다음 함수에 필요한 행과 열 수를 전달하십시오.

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(frame[,i])}
    if(type_vec[i] == 'character') {frame[,i] <- as.character(frame[,i])}
    if(type_vec[i] == 'logical') {frame[,i] <- as.logical(frame[,i])}
    if(type_vec[i] == 'factor') {frame[,i] <- as.factor(frame[,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"

1
이는 영업 이익의 요구 사항을 충족하지 않는 "나는 각 열의 데이터 유형을 지정하려면"
그레고르 토마스

6

동적 이름 (변수의 콜 이름)으로 빈 data.frame을 만들려면 다음을 수행하십시오.

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()

4

명시 적으로 데이터 유형을 지정하지 않으면 다음과 같이 할 수 있습니다.

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)

4

사용하여 data.table각 열에 대한 데이터 유형을 지정할 수 있습니다.

library(data.table)    
data=data.table(a=numeric(), b=numeric(), c=numeric())

3

data.frame많은 열이 있는 이러한을 선언 하려면 모든 열 클래스를 직접 입력하는 것이 어려울 것입니다. 특히 당신이 사용할 수있는 경우rep 이 방법은 쉽고 빠릅니다 (이와 같이 일반화 할 수있는 다른 솔루션보다 약 15 % 빠름).

원하는 열 클래스가 벡터 안에 있으면 colClasses다음을 수행 할 수 있습니다.

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

lapply원하는 길이의 목록이 생성되며 각 요소는 단순히 numeric()또는 같은 빈 유형의 벡터입니다.integer() 입니다.

setDFlist를 참조하여 이것을 변환 합니다 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

1

열 이름이 동적이라고 가정하면 빈 행 이름이 지정된 행렬을 만들어 데이터 프레임으로 변환 할 수 있습니다.

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

이는 영업 이익의 요구 사항을 충족하지 않는 "나는 각 열의 데이터 유형을 지정하려면"
그레고르 토마스

1

이 질문은 특별히 내 관심사를 다루지 않았지만 ( 여기서 설명되어 있음 ) 누구나 매개 변수가있는 열 수로 강제하지 않고이 작업을 수행하려는 경우 :

> require(dplyr)
> dbNames <- c('a','b','c','d')
> emptyTableOut <- 
    data.frame(
        character(), 
        matrix(integer(), ncol = 3, nrow = 0), stringsAsFactors = FALSE
    ) %>% 
    setNames(nm = c(dbNames))
> glimpse(emptyTableOut)
Observations: 0
Variables: 4
$ a <chr> 
$ b <int> 
$ c <int> 
$ d <int>

divibisan이 관련 질문에 대해 언급 한 것처럼

... [강제]가 발생하는 이유 [cbinding matrices와 그 구성 유형]는 행렬이 단일 데이터 유형 만 가질 수 있기 때문입니다. 2 개의 행렬을 결합해도 결과는 여전히 행렬이므로 데이터로 변환하기 전에 변수가 모두 단일 유형으로 강제 변환됩니다.


1

이미 데이터 프레임이 있다면 에서 메타 데이터 (열 이름 및 유형)추출 (예 : 특정 입력으로 만 트리거되고 빈 더미 데이터 프레임 이 필요한 BUG제어하는 경우 ).

colums_and_types <- sapply(df, class)

# prints: "c('col1', 'col2')"
print(dput(as.character(names(colums_and_types))))

# prints: "c('integer', 'factor')"
dput(as.character(as.vector(colums_and_types)))

그런 read.table다음를 사용하여 빈 데이터 프레임을 만듭니다.

read.table(text = "",
   colClasses = c('integer', 'factor'),
   col.names = c('col1', 'col2'))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.