एक खाली डेटा बनाएँ


480

मैं बिना किसी पंक्तियों के data.frame को इनिशियलाइज़ करने की कोशिश कर रहा हूँ। मूल रूप से, मैं प्रत्येक कॉलम के लिए डेटा प्रकार निर्दिष्ट करना चाहता हूं और उन्हें नाम देना चाहता हूं, लेकिन परिणामस्वरूप कोई पंक्तियां नहीं बनाई गई हैं।

अब तक मैं जो कुछ कर पाया हूं, वह सबसे अच्छा है:

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

जो एक एकल पंक्ति बनाता है जिसमें एक एकल पंक्ति होती है जिसमें सभी डेटा प्रकार और कॉलम नाम होते हैं जो मैं चाहता था, लेकिन एक बेकार पंक्ति भी बनाता है जिसे तब हटाने की आवश्यकता होती है।

क्या ऐसा करने के लिए इससे अच्छा तरीका है?

जवाबों:


651

बस इसे खाली वैक्टर से आरंभ करें:

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शून्य पंक्तियों के साथ भी काम करेगा ।


3
अगर मैं NULL के साथ सभी फ़ील्ड को इनिशियलाइज़ करूँ तो क्या यह वैसा ही होगा?
yosukesabai

8
@yosukesabai: नहीं, अगर आप एक कॉलम को NULL से जोड़ते हैं, तो कॉलम नहीं जोड़ा जाएगा :)
digEmAll

6
@yosukesabai: data.frameके टाइप किए हुए कॉलम हैं, इसलिए हां, अगर आप इनिशियलाइज़ करना चाहते हैं तो आपको data.frameकॉलम का प्रकार तय करना होगा ...
digEmAll

1
@jxramos: ठीक है, वास्तव data.frameमें स्तंभ प्रकारों की " प्रधानता " पर वास्तव में प्रतिबंध नहीं है (उदाहरण के लिए, आप तिथियों का एक स्तंभ या यहां तक ​​कि तत्वों की सूची वाला एक स्तंभ जोड़ सकते हैं)। इसके अलावा, यह प्रश्न एक पूर्ण संदर्भ नहीं है, उदाहरण के लिए यदि आप सही प्रकार के कॉलम को निर्दिष्ट नहीं करते हैं तो आप आगे पंक्ति को अलग-अलग प्रकार के कॉलम के अलावा ब्लॉक नहीं करेंगे ... इसलिए, मैं एक नोट जोड़ूंगा, लेकिन नहीं सभी आदिम प्रकारों के साथ एक उदाहरण क्योंकि यह सभी संभावनाओं को कवर नहीं करता है ...
digEmAll

3
@ user4050: प्रश्न एक खाली डेटा.फ्रेम बनाने के बारे में था, इसलिए जब पंक्तियों की संख्या शून्य हो ... हो सकता है कि आप NA पर एक डेटा.फ्रेम पूर्ण बनाना चाहते हों ... उस स्थिति में आप उपयोग कर सकते हैं जैसेdata.frame(Doubles=rep(as.double(NA),numberOfRow), Ints=rep(as.integer(NA),numberOfRow))
digEmAll

140

यदि आपके पास पहले से मौजूद डेटा फ़्रेम है , तो मान लें dfकि आपके पास इच्छित कॉलम हैं, तो आप सभी पंक्तियों को हटाकर एक खाली डेटा फ़्रेम बना सकते हैं:

empty_df = df[FALSE,]

ध्यान दें कि dfअभी भी डेटा शामिल है, लेकिन empty_dfनहीं है।

मुझे यह सवाल मिला कि खाली पंक्तियों के साथ एक नया उदाहरण कैसे बनाया जाए, इसलिए मुझे लगता है कि यह कुछ लोगों के लिए मददगार हो सकता है।


2
अद्भुत विचार है। पंक्तियों में से कोई भी नहीं रखें, लेकिन सभी कॉलम। जो कोई नीचे गिरा वह कुछ चूक गया।
राम नरसिम्हन

1
अच्छा समाधान, हालांकि मैंने पाया कि मुझे 0 पंक्तियों के साथ एक डेटा फ़्रेम मिलता है। डेटा फ्रेम का आकार समान रखने के लिए, मैं new_df = df [NA]] का सुझाव देता हूं। यह किसी भी पिछले कॉलम को नए डेटा फ़्रेम में संग्रहीत करने की अनुमति देता है। उदाहरण के लिए "दिनांक" कॉलम को मूल df (बाकी NA रखते हुए) से प्राप्त करने के लिए: new_df $ Date <- df $ Date।
कट्या

2
@ कट्य, यदि आप ऐसा df[NA,]करते हैं तो सूचकांक को भी प्रभावित करेगा (जो आप चाहते हैं वह होने की संभावना नहीं है), मैं इसके बजाय उपयोग करूंगा df[TRUE,] = NA; हालाँकि, ध्यान दें कि यह मूल को अधिलेखित कर देगा। आपको पहले copy_df = data.frame(df)copy_df[TRUE,] = NA
डेटाफ्रेम

3
@Katya हैं, या आप भी आसानी से खाली पंक्तियों को जोड़ सकते हैं empty_dfके साथ empty_df[0:nrow(df),] <- NA
toto_tico

1
@ कटिया, आप एक backquote (`) का उपयोग करते हैं, जो आप कोड के रूप में चिह्नित करना चाहते हैं, और * का उपयोग करके इटैलिक के रूप में अन्य सामान है , और ** का उपयोग करके बोल्ड है । आप शायद SO के सभी Markdown सिंटेक्स को पढ़ना चाहते हैं । हालांकि यह ज्यादातर केवल उत्तर के लिए समझ में आता है।
टोटू_टिको

79

आप इसे कॉलम प्रकार निर्दिष्ट किए बिना कर सकते हैं

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

4
उस स्थिति में, स्तंभ प्रकार तार्किक प्रति वेक्टर के रूप में डिफ़ॉल्ट () है, लेकिन फिर df में जोड़े गए तत्वों के प्रकार के साथ ओवरराइड किया जाता है। प्रयास करें str (df), df [1,1] <- 'x'
डेव 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)

सुधार के लिए रिचर्ड स्क्रिपन को धन्यवाद


4
या यहां तक read.table(text = "", ...)कि आपको स्पष्ट रूप से कनेक्शन खोलने की आवश्यकता नहीं है।
रिच स्क्रीवेन

अत्यधिक आकर्षित। संभवत: कई संभावित स्तंभों के लिए ऐसा करने का सबसे एक्स्टेंसिबल / ऑटोमैटिक तरीका है
माइकलक्रिको

3
read.csvदृष्टिकोण भी साथ काम करता है readr::read_csvके रूप में, read_csv("Date,File,User\n", col_types = "Dcc")। इस तरह आप सीधे आवश्यक संरचना का एक खाली टिबेल बना सकते हैं।
हीथ टर्नर

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फ़ंक्शन को कॉल किए बिना फ़ेक नहीं किया जा सकता है। क्या आप सुनिश्चित हैं कि आप यहाँ एक अनैच्छिक व्यवहार पर भरोसा नहीं कर रहे हैं?
एडम रिक्ज़ोस्की

@AdamRyczkowski मुझे लगता है कि आप आधार "data.frame" वर्ग और data.table पैकेज से "data.table" वर्ग को भ्रमित कर रहे हैं ।
थॉमस

हाँ। निश्चित रूप से। मेरी गलती। मेरी पिछली टिप्पणी को नजरअंदाज करें। मैं इस धागे को खोजते हुए आया data.tableऔर यह मान लिया कि Google को वही मिला है जो मैं चाहता था और यहाँ सब कुछ data.tableसंबंधित है।
एडम रिक्ज़ोस्की

1
@PatrickT कोई जाँच नहीं है कि आपका कोड क्या कर रहा है इसका कोई मतलब नहीं है। data.frame()नामकरण, रांगनाम, आदि पर चेक प्रदान करता है
थॉमस

26

बस घोषणा करते हैं

table = data.frame()

जब आप rbindपहली पंक्ति में प्रयास करेंगे तो यह कॉलम बनाएगा


2
क्या वास्तव में "मैं प्रत्येक कॉलम के लिए डेटा प्रकार निर्दिष्ट करना चाहता हूं और उन्हें नाम देना चाहता हूं" ओपी की आवश्यकताओं को पूरा नहीं करता है। यदि अगला कदम rbindयह है तो यह अच्छा काम करेगा, यदि नहीं ...
ग्रेगर थॉमस

वैसे भी, इस सरल समाधान के लिए धन्यवाद। मैं यह भी चाहता था कि किसी विशिष्ट कॉलम के साथ एक डेटा.फ्रेम को इनिशियलाइज़ किया जाए क्योंकि मैंने सोचा था कि rbind का उपयोग केवल तभी किया जा सकता है जब कॉलम दो डेटा के बीच मेल खाता हो। ऐसा नहीं लगता है। मुझे आश्चर्य था कि मैं rbind का उपयोग करते समय बस एक data.frame को इनिशियलाइज़ कर सकता हूं। धन्यवाद।
जियोर्डानो

4
सबसे अच्छा प्रस्तावित समाधान यहाँ। मेरे लिए, प्रस्तावित तरीके का उपयोग करते हुए, पूरी तरह से साथ काम किया rbind()
कोट्स

17

यदि आप कमी की तलाश कर रहे हैं:

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

इसलिए आपको कॉलम नामों को अलग से निर्दिष्ट करने की आवश्यकता नहीं है। जब तक आप डेटा फ़्रेम नहीं भरते, तब तक आपको डिफ़ॉल्ट कॉलम टाइप लॉजिकल मिलता है।


read.csv पाठ तर्क को पार्स करता है ताकि आपको कॉलम नाम मिलें। यह read.table की तुलना में अधिक कॉम्पैक्ट है (पाठ = "", col.names = c ( "col1", "col2"))
मार्क

मुझे मिलता है:Error in data.frame(..., check.names = FALSE) : arguments imply differing number of rows: 0, 2
Climbs_lika_Spyder

यह ओपी की आवश्यकताओं को पूरा नहीं करता है, "मैं प्रत्येक कॉलम के लिए डेटा प्रकार निर्दिष्ट करना चाहता हूं" , हालांकि इसे ऐसा करने के लिए संशोधित किया जा सकता है।
ग्रेगर थॉमस

14

मैंने निम्नलिखित कोड का उपयोग करके खाली डेटा फ़्रेम बनाया

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

और कुछ पंक्तियों को उसी तरह से पॉप्युलेट करने के लिए बाँधने की कोशिश की।

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

लेकिन इसने गलत कॉलम नाम देना शुरू कर दिया

  X3 X4
1  3  4

इसका समाधान निम्न प्रकार से df टाइप करने के लिए newrow कन्वर्ट करना है

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

यदि आप डायनामिक नामों (किसी चर में कॉलनेम) के साथ एक खाली डेटा बनाना चाहते हैं, तो यह मदद कर सकता है:

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>

जैसा कि विभिषण ने संबंधित प्रश्न पर कहा,

... कारण [बलात्कार] तब होता है [जब मैट्रिक और उनके घटक प्रकारों को सिलना] यह है कि एक मैट्रिक्स में केवल एक ही डेटा प्रकार हो सकता है। जब आप 2 मैट्रिस् को cbind करते हैं, तो परिणाम अभी भी एक मैट्रिक्स है और इसलिए चर सभी डेटा के लिए कनवर्ट करने से पहले एक ही प्रकार में coerced हैं


1

यदि आपके पास पहले से ही एक डेटाफ्रेम है, तो आप मेटाडेटा (कॉलम नाम और प्रकार) को एक डेटाफ्रेम से निकाल सकते हैं (जैसे यदि आप एक बीयूजी को नियंत्रित कर रहे हैं जो केवल कुछ इनपुट के साथ चालू होता है और एक खाली डमी डेटाफ्रेम की आवश्यकता होती है):

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'))
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.