从一个数据框中的多个 .csv 和 cbind 中提取相同的列(不同长度)- R

extract the same column (different length) from multiple .csv and cbind in one data frame - R

所以我有 1300 csv-files 个财务数据,格式如下:

          Date     Open     High      Low    Close
1 Nov 28, 2017 0.233394 0.234871 0.223832 0.225542 
2 Nov 27, 2017 0.225910 0.234219 0.212298 0.233113
3 Nov 26, 2017 0.229367 0.235126 0.215153 0.226367
4 Nov 25, 2017 0.234212 0.239257 0.223383 0.228617
5 Nov 24, 2017 0.215836 0.236280 0.209834 0.234195
6 Nov 23, 2017 0.228887 0.232974 0.214334 0.216585

我的目标是从每个文件中提取列 "Open" 并将这些列绑定在一起,使其看起来像这样:

     Date     "File1"   "File2"  "File3"  ... "File 1300"         
1 Nov 28, 2017 0.233394 0.234871 0.223832 ... 0.225542 
2 Nov 27, 2017 0.225910 0.234219 0.212298 ... 0.233117 
3 Nov 26, 2017 0.229367 0.235126 0.215153 ... 0.226367 
4 Nov 25, 2017 0.234212 NA       0.223383 ... 0.228617 
5 Nov 24, 2017 0.215836 NA       0.209834 ... 0.234195 
6 Nov 23, 2017 0.228887 NA       0.214334 ... NA

我知道这里已经有很多关于如何从多个 csv-files 中提取列以及如何将它们绑定在一起的问题,我几乎就在那里,但问题是文件不同,因为我有基于日期的观察。例如,一个文件可以包含 2014 年 Des 3 的观测值,而另一个文件可以包含 2017 年 11 月 23 日的观测值。否则,文件在格式方面是相同的,并且它们的最后一次观测值都在 2017 年 11 月 28 日。

到目前为止你可以在下面看到我的代码

# Get a List of all files in directory 
filenames <- list.files(".../path, pattern="*.csv", full.names=F)

# Loading column "Open" from each file 
for(i in filenames){   
    filepath <- file.path(".../path", paste(i,sep=""))   
    assign(i, read.csv(filepath, header=T, sep = ";", 
        colClasses=c(NA, NA, "NULL", "NULL", "NULL"))) 
}

#making a list of all data frames
df_list <- lapply(ls(), function(x) if (class(get(x)) == "data.frame") get(x)) 

#merging  
library(dplyr) 
res2 <- Reduce(function(...) left_join(..., by=c("Date")), df_list)

如您所见,我将所有 csv-files 加载到全局环境中并将其添加到列表中,然后我想将其中的列合并到一个数据框中。问题似乎是合并部分,其中 Reduce 或 dplyr-package 似乎无法解决问题。

所以我的问题是,您是否有任何解决方案可以将所有 Date-columns 列绑定到一个数据框中并按日期排序?而且,是否有任何快速修复方法可以将列的文件名设置为 headers ?

我也不确定 R 是否是解决此问题的最佳方法。我不太熟悉 Python,但如果你觉得它更简单,我可以尝试使用它。

这是未经测试的。关于如何导入的两种方法。一个是使用 for 循环迭代,而第二个是导入所有数据,然后使用 Reduce 将 2. 对象合并到第一个,第三个合并 1. 和 2.,第四个合并 1., 2.和 3.等等。

# approach #1
result <- read.csv(filenames[1], header = TRUE, sep = ";")[, c("Date", "Open")]

for (i in filenames[-1]) {
  out <- read.csv(i, header = TRUE, sep = ";")[, c("Date", "Open")]
  colnames(out) <- c("Date", basename(filenames[i]))
  result <- merge(result, by = "Date")
}


# approach #2
alldata <- lapply(filenames, FUN = function(x) {
  out <- read.csv(i, header = TRUE, sep = ";")[, c("Date", "Open")]
  colnames(out) <- c("Date", basename(x))
  out
})

result <- Reduce(function(dtf1, dtf2) merge(dtf1, dtf2, by = "Date", all = TRUE), alldata)

如果您也对 Python 中的解决方案感兴趣,请点击此处。我刚刚测试了它,它似乎有效:

首先,您需要将 csv 文件读入 pandas,假设列 0、1 是日期和打开,skipinitialspace=True 只是去掉了空格。因为我们想要一个包含数据框的列表,所以我们遍历 csv 文件:

dfs = []
for files in glob.glob('*.csv'):
    dfs.append(pd.read_csv('./' + files, delimiter=';', usecols=[0, 1], skipinitialspace=True))

阅读完所有文件后,您想更改列名以反映文件名:

dfs = [x.rename(columns={'Open': 'File_{}'.format(i)}) for i, x in enumerate(dfs)]

现在,礼貌到这里pandas joining multiple dataframes on columns 您可以减少以创建最终数据框:

df_final = reduce(lambda left,right: pd.merge(left,right,on='Date', how='outer'), dfs)

这将创建一个最终数据框

这里是另一种使用时间序列库的方法 (zoo)。

首先我准备一些和你类似的数据:

library(quantmod)

getSymbols(c("MSFT","FB"),src='yahoo',from='2005-01-01')
MSFT=data.frame(Dt=strftime(time(MSFT),format = "%b %d, %Y"),
                Close=unname(MSFT[,"MSFT.Close"]))
rownames(MSFT)=NULL
FB=data.frame(Dt=strftime(time(FB),format = "%b %d, %Y"),
              Close=unname(FB[,"FB.Close"]))
rownames(FB)=NULL
write.csv(MSFT,file="MSFT.csv",row.names = FALSE)
write.csv(FB,file="FB.csv",row.names = FALSE)

现在正式回答您的问题:

#answer to original question
library(zoo)

filenames=c("MSFT.csv","FB.csv")

finDataList=lapply(filenames,function(x) 
    read.csv.zoo(x,format="%b %d, %Y",drop=FALSE))

finData=do.call("merge",finDataList)
colnames(finData)=gsub("\.csv","",filenames)
head(finData)
#             MSFT FB
# 2005-01-03 26.74 NA
# 2005-01-04 26.84 NA
# 2005-01-05 26.78 NA
# 2005-01-06 26.75 NA
# 2005-01-07 26.67 NA
# 2005-01-10 26.80 NA