在R中使用空数据帧

时间:2018-06-23 09:18:51

标签: r dataframe

我试图在for loop外部定义一个空的df,然后从循环内部填充行/列,如下所示:

df<- data.frame()
    for (fl in files){
      dt <- read.table(fl, header = FALSE, col.names = c("year","month","value"),
       colClasses = c("character","character","numeric"))
      t <- aggregate(value ~ year, dt, sum)
      df$year <- t$year
      df$value <- t$value * someFunction() 
    }

现在,有多种方法可以在R中创建空df。

df <- data.frame()

# or another method
df <- data.frame(Month=character(), 
                 Value=character(), 
                 stringsAsFactors=FALSE) 

# or another method
df <- data.frame(matrix(nrow = 0, ncol = 2))

但是当我为数据框分配值时,会产生以下错误:

df$Month <- month.abb

Error in `$<-.data.frame`(`*tmp*`, File, value = c("Jan", "Feb", "Mar",  : 
  replacement has 12 rows, data has 0

我不知道自己在做错什么或可能会有任何误解,但我找不到解决方法。有人可以向我解释吗?

P.S:df <- data.frame(matrix(nrow = 100, ncol = 2))可以工作,但是我不知道这是一个好主意,因为我的df的行数会有所不同。

4 个答案:

答案 0 :(得分:2)

您需要将这些值添加到for循环中的列表中,然后可以将这些行作为数据框绑定在一起。像这样:

myList <- list()

for (m in 1:length(month.abb)) {
  myList[[m]] <- month.abb[m]

}

df <- as.data.frame(do.call(rbind, myList))

答案 1 :(得分:2)

如果需要对多个输入文件执行相同的一组计算,则可以使用apply()函数来完成此操作,而无需进行for()循环。

为说明起见,我们将使用他发布到Kaggle的Alberto Barradas的Pokémon with stats数据库中的数据。我使用的实际CSV文件可以在PokémonData github repository上访问。

我将数据分为6个单独的CSV文件,每代神奇宝贝一个。为了使示例完全可重现,请先下载文件,然后将其存储在R Working Directory的子目录中。

我们将使用list.files()读取文件名,这样我们就可以处理数量可变的文件,而无需手动编辑文件名,并将结果用作输入到lapply()的文件。我们还将使用匿名函数来读取数据并执行其他计算。

lapply()的输出是一个数据帧的列表,可以随后对其进行单独处理,或与do.call()合并为一个数据帧,如其他答案之一所示。

download.file("https://raw.githubusercontent.com/lgreski/pokemonData/master/pokemonData.zip",
              "pokemonData.zip",
              method="curl",mode="wb")
unzip("pokemonData.zip")

thePokemonFiles <- list.files("./pokemonData",
                              full.names=TRUE)    
pokemonDataFiles <- lapply(thePokemonFiles,function(x) {
     y <- read.csv(x,stringsAsFactors=FALSE)
     y$speedSquared <- y$Speed^2
     y # return data frame to result object
     })
head(pokemonDataFiles[[1]])

...以及输出:

> head(pokemonDataFiles[[1]])
  Number                  Name Type1  Type2 Total HP Attack Defense SpecialAtk SpecialDef Speed Generation Legendary
1      1             Bulbasaur Grass Poison   318 45     49      49         65         65    45          1     False
2      2               Ivysaur Grass Poison   405 60     62      63         80         80    60          1     False
3      3              Venusaur Grass Poison   525 80     82      83        100        100    80          1     False
4      3 VenusaurMega Venusaur Grass Poison   625 80    100     123        122        120    80          1     False
5      4            Charmander  Fire          309 39     52      43         60         50    65          1     False
6      5            Charmeleon  Fire          405 58     64      58         80         65    80          1     False
  speedSquared
1         2025
2         3600
3         6400
4         6400
5         4225
6         6400
> 

披露:此代码基于我在2017年的博客文章Forms of the Extract Operator中发布的代码。

答案 2 :(得分:1)

有4种方法来发展data.frame

col1 <- letters[1:3] # [1] "a" "b" "c"
col2 <- letters[4:6] # [1] "d" "e" "f"

1-首先分配第一列

df1 <- data.frame(col1,stringsAsFactors = FALSE)
df1$col2 <- col2

2-首先增加列表,然后进行转换

l2 <- list()
l2$col1 <- col1
l2$col2 <- col2
df2 <- data.frame(l2,stringsAsFactors = FALSE)

3-使用以正确长度开始的列定义data.frame:

df3 <- data.frame(col1 = character(3), col2 = character(3))
df3$col1 <- col1
df3$col2 <- col2

4-定义行名称时要设置它,使其具有0列和n行

df4 <- data.frame(row.names = 1:3)
df4$col1 <- col1
df4$col2 <- col2

检查是否等同:

identical(df1,df2) # [1] TRUE
identical(df1,df3) # [1] TRUE
identical(df1,df4) # [1] TRUE

答案 3 :(得分:0)

有帮助吗?

months = c("Jan","Feb","Mar")

df <- data.frame(Month=character(), 
             Value=character(), 
             stringsAsFactors=FALSE)

for (i in 1:length(months)){

    df[i,1] = months[i]
}