假设我正在处理一个非常大的csv文件。因此,我只能逐块读取数据到内存中。预期的事件流应如下:
1)使用熊猫从csv读取数据块(例如10行)。
2)颠倒数据顺序
3)反向将每一行复制到新的csv文件。所以每个块(10行)是 从一开始就以相反的顺序写入csv。
最后,csv文件应以相反的顺序进行,并且应在不将整个文件加载到Windows OS内存的情况下完成。
我正在尝试进行时间序列预测,因此我需要数据从旧到最新(第一行最早的条目)。我无法将整个文件加载到内存中,我正在寻找一种在可能的情况下一次处理每个块的方法。
我在kaggle的Rossmann dataset中的train.csv
上尝试过的数据集。您可以从此github repo
我的尝试未将行正确复制到新的csv文件中。
下面显示的是我的代码:
import pandas as pd
import csv
def reverse():
fields = ["Store","DayOfWeek","Date","Sales","Customers","Open","Promo","StateHoliday",
"SchoolHoliday"]
with open('processed_train.csv', mode='a') as stock_file:
writer = csv.writer(stock_file,delimiter=',', quotechar='"',
quoting=csv.QUOTE_MINIMAL)
writer.writerow(fields)
for chunk in pd.read_csv("train.csv", chunksize=10):
store_data = chunk.reindex(index=chunk.index[::-1])
append_data_csv(store_data)
def append_data_csv(store_data):
with open('processed_train.csv', mode='a') as store_file:
writer = csv.writer(store_file,delimiter=',', quotechar='"',
quoting=csv.QUOTE_MINIMAL)
for index, row in store_data.iterrows():
print(row)
writer.writerow([row['Store'],row['DayOfWeek'],row['Date'],row['Sales'],
row['Customers'],row['Open'],row['Promo'],
row['StateHoliday'],row['SchoolHoliday']])
reverse()
提前谢谢
答案 0 :(得分:4)
使用bash,您可以拖尾整个文件(第一行除外),然后将其反转并以此存储:
tail -n +2 train.csv | tac > train_rev.csv
如果要将标题保留在反向文件中,请先将其写入,然后附加反向内容
head -1 train.csv > train_rev.csv; tail -n +2 train.csv | tac >> train_rev.csv
答案 1 :(得分:0)
如果有足够的硬盘空间,则可以分块读取,反向存储。然后以相反的顺序拾取存储的块并写入新的csv文件。
下面是Pandas的示例,该示例还使用了pickle(提高性能)和gzip(提高存储效率)。
import pandas as pd, numpy as np
# create a dataframe for demonstration purposes
df = pd.DataFrame(np.arange(5*9).reshape((-1, 5)))
df.to_csv('file.csv', index=False)
# number of rows we want to chunk by
n = 3
# iterate chunks, output to pickle files
for idx, chunk in enumerate(pd.read_csv('file.csv', chunksize=n)):
chunk.iloc[::-1].to_pickle(f'file_pkl_{idx:03}.pkl.gzip', compression='gzip')
# open file in amend mode and write chunks in reverse
# idx stores the index of the last pickle file written
with open('out.csv', 'a') as fout:
for i in range(idx, -1, -1):
chunk_pkl = pd.read_pickle(f'file_pkl_{i:03}.pkl.gzip', compression='gzip')
chunk_pkl.to_csv(fout, index=False, header=False if i!=idx else True)
# read new file to check results
df_new = pd.read_csv('out.csv')
print(df_new)
0 1 2 3 4
0 40 41 42 43 44
1 35 36 37 38 39
2 30 31 32 33 34
3 25 26 27 28 29
4 20 21 22 23 24
5 15 16 17 18 19
6 10 11 12 13 14
7 5 6 7 8 9
8 0 1 2 3 4
答案 2 :(得分:0)
我不建议您使用pandas
来解析或流式传输任何文件,因为您只是引入了额外的开销。最好的方法是从下至上读取文件。好吧,这段代码的大部分实际上来自here,在这里它接收一个文件并在生成器中返回相反的值,我相信这就是您想要的。
我所做的只是使用您提供的链接中的文件train.csv
对它进行了测试,并将结果输出到新文件中。
import os
def reverse_readline(filename, buf_size=8192):
"""a generator that returns the lines of a file in reverse order"""
with open(filename) as fh:
segment = None
offset = 0
fh.seek(0, os.SEEK_END)
file_size = remaining_size = fh.tell()
while remaining_size > 0:
offset = min(file_size, offset + buf_size)
fh.seek(file_size - offset)
buffer = fh.read(min(remaining_size, buf_size))
remaining_size -= buf_size
lines = buffer.split('\n')
# the first line of the buffer is probably not a complete line so
# we'll save it and append it to the last line of the next buffer
# we read
if segment is not None:
# if the previous chunk starts right from the beginning of line
# do not concact the segment to the last line of new chunk
# instead, yield the segment first
if buffer[-1] != '\n':
lines[-1] += segment
else:
yield segment
segment = lines[0]
for index in range(len(lines) - 1, 0, -1):
if lines[index]:
yield lines[index]
# Don't yield None if the file was empty
if segment is not None:
yield segment
reverse_gen = reverse_readline('train.csv')
with open('rev_train.csv','w') as f:
for row in reverse_gen:
f.write('{}\n'.format(row))
它基本上是反向读取,直到找到换行符,然后从下到上从文件中产生line
。一种非常有趣的方式。
答案 3 :(得分:0)
这完全符合您的要求,但没有熊猫。它逐行读取intest.csv(与将整个文件读取到RAM相对)。它使用文件系统来执行大部分处理,该文件系统使用一系列块文件,这些块文件最后汇总到outtest.csv文件中。如果更改maxLines,则可以优化生成的块文件数与消耗的RAM(数量越大,消耗的RAM越多,但生成的块文件越少)。如果要保留CSV标头的第一行,请将keepHeader设置为True;如果设置为False,它将反转整个文件,包括第一行。
为了踢一下,我在6MB csv测试文件上使用128GB闪存驱动器的旧Raspberry Pi上运行了该程序,我认为出了点问题,因为它几乎立即返回,因此即使在较慢的硬件上也很快。它仅导入一个标准的python库函数(删除),因此非常易于移植。此代码的优点之一是它不会重新放置任何文件指针。一个限制是它不适用于数据中包含换行符的CSV文件。对于这种用例,熊猫将是读取块的最佳解决方案。
from os import remove
def writechunk(fileCounter, reverseString):
outFile = 'tmpfile' + str(fileCounter) + '.csv'
with open(outFile, 'w') as outfp:
outfp.write(reverseString)
return
def main():
inFile = 'intest.csv'
outFile = 'outtest.csv'
# This is our chunk expressed in lines
maxLines = 10
# Is there a header line we want to keep at the top of the output file?
keepHeader = True
fileCounter = 0
lineCounter = 0
with open(inFile) as infp:
reverseString = ''
line = infp.readline()
if (line and keepHeader):
headerLine = line
line = infp.readline()
while (line):
lineCounter += 1
reverseString = line + reverseString
if (lineCounter == maxLines):
fileCounter += 1
lineCounter = 0
writechunk(fileCounter, reverseString)
reverseString = ''
line = infp.readline()
# Write any leftovers to a chunk file
if (lineCounter != 0):
fileCounter += 1
writechunk(fileCounter,reverseString)
# Read the chunk files backwards and append each to the outFile
with open(outFile, 'w') as outfp:
if (keepHeader):
outfp.write(headerLine)
while (fileCounter > 0):
chunkFile = 'tmpfile' + str(fileCounter) + '.csv'
with open(chunkFile, 'r') as infp:
outfp.write(infp.read())
remove(chunkFile)
fileCounter -= 1
if __name__ == '__main__':
main()
答案 4 :(得分:-3)
您重复了代码块,并且根本没有利用熊猫。
@sujay kumar指出的是非常正确的,我会仔细阅读。
文件根本不大。我使用的GB的OHLCV刻度数据没有问题。如果您使用pandas.read_csv()
,则不必进行分块传输。当然,这将需要一些时间,但效果会很好。除非您要使用Terrabytes。我尚未对此进行测试。
read_csv()
时,您不指定任何索引。如果您这样做了,则可以致电sort_index()
,有无ascending=False
,具体取决于顺序。
熊猫也可以编写CSV,请改用CSV。我正在粘贴一些示例代码供您组合。
df_temp = pd.read_csv(file_path, parse_dates=True, index_col="Date",
usecols=["Date", "Adj Close"], na_values=["nan"])
对系列进行排序
s = pd.Series(list('abcde'), index=[0,3,2,5,4])
s.sort_index()
注意:如果您坚持使用Pandas及其功能,则将运行已经优化的代码,不需要将整个文件加载到内存中。非常容易,几乎就像作弊:)