在 for 循环中将数据帧附加在一起
Posted
技术标签:
【中文标题】在 for 循环中将数据帧附加在一起【英文标题】:Append data frames together in a for loop 【发布时间】:2015-06-06 19:01:41 【问题描述】:我有一个for loop
,它会在每次迭代后生成一个数据框。我想将所有数据帧附加在一起,但发现很难。以下是我
正在尝试,请建议如何解决它:
d = NULL
for (i in 1:7)
# vector output
model <- #some processing
# add vector to a dataframe
df <- data.frame(model)
df_total <- rbind(d,df)
【问题讨论】:
【参考方案1】:你应该试试这个:
df_total = data.frame()
for (i in 1:7)
# vector output
model <- #some processing
# add vector to a dataframe
df <- data.frame(model)
df_total <- rbind(df_total,df)
【讨论】:
它在单列中逐帧附加。如何将所有数据框附加到单独的列中? 使用 cbind() 代替 rbind() 使用cbind()
导致Error in data.frame(..., check.names = FALSE) : arguments imply differing number of rows: 0, 18262
您是否在重新执行循环之前重置了 df_total = data.frame()?
不重置,for loop
的每次迭代都会给出相同的行数【参考方案2】:
同样,马丁是正确的,但要使其正常工作,您必须从一个已经有至少一列的数据框开始
model <- #some processing
df <- data.frame(col1=model)
for (i in 2:17)
model <- # some processing
nextcol <- data.frame(model)
colnames(nextcol) <- c(paste("col", i, sep="")) # rename the comlum
df <- cbind(df, nextcol)
【讨论】:
它可以工作,但会将数据附加到单个列中。我希望所有数据框都在单独的列中【参考方案3】:不要在循环内这样做。列一个列表,然后在循环外将它们组合起来。
datalist = list()
for (i in 1:5)
# ... make some data
dat <- data.frame(x = rnorm(10), y = runif(10))
dat$i <- i # maybe you want to keep track of which iteration produced it?
datalist[[i]] <- dat # add it to your list
big_data = do.call(rbind, datalist)
# or big_data <- dplyr::bind_rows(datalist)
# or big_data <- data.table::rbindlist(datalist)
这是一种更像 R 的做事方式。它也可以大大加快,特别是如果您使用dplyr::bind_rows
或data.table::rbindlist
进行数据帧的最终组合。
【讨论】:
它也可以,但我想将所有列表写入单独的列 @Ibe 你真的应该编辑你的问题。提供示例数据和所需的输出(请参阅我在马丁的回答中的评论)并把rbind
排除在您的问题之外,因为所有rbind
所做的都是将行绑定在一起。
刚刚将代码中的rbind
替换为cbind
。它有效,现在我将所有列表放在单独的列中
同样,如果这一步你觉得慢,试试dplyr::bind_cols()
,
do.call(rbind, datalist)
是一种很好的写作方式rbind(datalist[[1]], datalist[[2]], datalist[[3]], ...)
【参考方案4】:
在 Coursera 课程“R 编程简介”中,对这项技能进行了测试。 他们给所有学生 332 个单独的 csv 文件,并要求他们以编程方式组合几个文件来计算污染物的平均值。
这是我的解决方案:
# create your empty dataframe so you can append to it.
combined_df <- data.frame(Date=as.Date(character()),
Sulfate=double(),
Nitrate=double(),
ID=integer())
# for loop for the range of documents to combine
for(i in min(id): max(id))
# using sprintf to add on leading zeros as the file names had leading zeros
read <- read.csv(paste(getwd(),"/",directory, "/",sprintf("%03d", i),".csv", sep=""))
# in your loop, add the files that you read to the combined_df
combined_df <- rbind(combined_df, read)
【讨论】:
将它们全部读入一个列表然后将它们全部组合起来会更有效。【参考方案5】:尝试使用rbindlist
方法而不是rbind
,因为它非常非常快。
例子:
library(data.table)
##### example 1: slow processing ######
table.1 <- data.frame(x = NA, y = NA)
time.taken <- 0
for( i in 1:100)
start.time = Sys.time()
x <- rnorm(100)
y <- x/2 +x/3
z <- cbind.data.frame(x = x, y = y)
table.1 <- rbind(table.1, z)
end.time <- Sys.time()
time.taken <- (end.time - start.time) + time.taken
print(time.taken)
> Time difference of 0.1637917 secs
####example 2: faster processing #####
table.2 <- list()
t0 <- 0
for( i in 1:100)
s0 = Sys.time()
x <- rnorm(100)
y <- x/2 + x/3
z <- cbind.data.frame(x = x, y = y)
table.2[[i]] <- z
e0 <- Sys.time()
t0 <- (e0 - s0) + t0
s1 = Sys.time()
table.3 <- rbindlist(table.2)
e1 = Sys.time()
t1 <- (e1-s1) + t0
t1
> Time difference of 0.03064394 secs
【讨论】:
【参考方案6】:这里有一些 tidyverse
和自定义函数选项,它们可能会根据您的需要起作用:
library(tidyverse)
# custom function to generate, filter, and mutate the data:
combine_dfs <- function(i)
data_frame(x = rnorm(5), y = runif(5)) %>%
filter(x < y) %>%
mutate(x_plus_y = x + y) %>%
mutate(i = i)
df <- 1:5 %>% map_df(~combine_dfs(.))
df <- map_df(1:5, ~combine_dfs(.)) # both give the same results
> df %>% head()
# A tibble: 6 x 4
x y x_plus_y i
<dbl> <dbl> <dbl> <int>
1 -0.973 0.673 -0.300 1
2 -0.553 0.0463 -0.507 1
3 0.250 0.716 0.967 2
4 -0.745 0.0640 -0.681 2
5 -0.736 0.228 -0.508 2
6 -0.365 0.496 0.131 3
如果你有一个需要合并的文件目录,你可以做类似的事情:
dir_path <- '/path/to/data/test_directory/'
list.files(dir_path)
combine_files <- function(path, file)
read_csv(paste0(path, file)) %>%
filter(a < b) %>%
mutate(a_plus_b = a + b) %>%
mutate(file_name = file)
df <- list.files(dir_path, '\\.csv$') %>%
map_df(~combine_files(dir_path, .))
# or if you have Excel files, using the readxl package:
combine_xl_files <- function(path, file)
readxl::read_xlsx(paste0(path, file)) %>%
filter(a < b) %>%
mutate(a_plus_b = a + b) %>%
mutate(file_name = file)
df <- list.files(dir_path, '\\.xlsx$') %>%
map_df(~combine_xl_files(dir_path, .))
【讨论】:
函数combine_files
对单个文件进行操作并且不与任何内容组合时,它似乎很奇怪......【参考方案7】:
x <- c(1:10)
# empty data frame with variables ----
df <- data.frame(x1=character(),
y1=character())
for (i in x)
a1 <- c(x1 == paste0("The number is ",x[i]),y1 == paste0("This is another number ", x[i]))
df <- rbind(df,a1)
names(df) <- c("st_column","nd_column")
View(df)
这可能是一个很好的方法......
【讨论】:
我没有对这篇文章投票(仅编辑了它的格式),但是从代码的角度和答案的角度来看,它都有一些问题。对于代码,<-
不在函数调用中命名参数(例如c()
),而是赋值运算符(命名参数使用=
)。从答案的角度来看,在循环中调用rbind
与西蒙的答案基本相同。【参考方案8】:
对我来说,它非常简单。起初,我创建了一个空的data.frame
,然后在每次迭代中我添加了一列。这是我的代码:
df <- data.frame(modelForOneIteration)
for(i in 1:10)
model <- # some processing
df[,i] = model
【讨论】:
【参考方案9】:"""通过 Groupby 从唯一的 TF 生成多个 DataFrame"""
i=0
dfs_list=[]
for i in range(i,len(df_CDL)):
df = df_CDL[i]
print(df,'Only 1 df_CDL')
dfs= []
for _, dataframe in df.groupby('TFs'):
print('What is going on here?15',dataframe)
dfs.append([dataframe])
dfs_list.append([dfs])
#Index 任何你想要的数据框或遍历它们。随便..
print('Test?10', dfs[1], 'Test?20')
print('What is going on here? 1', dfs_list[5], 'What is
going on here again? 2')
【讨论】:
以上是关于在 for 循环中将数据帧附加在一起的主要内容,如果未能解决你的问题,请参考以下文章
pyspark 在 for 循环下的每个进程之后附加非常大的多个数据帧(例如:在每日 ETL 之后附加)