我有一个这样的输入文件:
a
1,100
2,200
3,300
b
1,100,200
2,200,300
3,300,400
c
...
我想使用以下代码将文件读取到多个数据帧中(为简化问题,我们假设每个表的行数是固定的):
import pandas as pd
with open("file.csv", "r") as f:
while True:
table_name = f.readline()
if table_name:
table_df = pd.read_csv(f, nrows=3)
# Do other stuff
else:
break
我最初的期望是pd.read_csv(f, nrows=3)
仅消耗输入流中有限数量的行,并且下一个f.readline()
调用将继续进行。但是,事实证明,在第一次read_csv
调用之后,f
的流位置被设置为文件的末尾,并且我无法再从同一流f
中读取。我的熊猫版本是0.25.0。这是错误还是预期的行为?有什么方法可以重用相同的输入流来读取多个数据帧?
答案 0 :(得分:3)
pandas.read_csv将从filepath_or_buffer
参数一次创建文件 reader 对象,而nrows=
param仅提供获取阅读器的一个切片(它无法从同一文件对象重新实例化新的阅读器)
通过类似文件的对象,我们使用
read()
方法引用对象,例如 作为文件处理程序(例如,通过内置的open
函数)或StringIO
。
根据您的输入文件格式,假设将table_name
视为具有单个字符串且不带分隔符,
(即a
,b
)的行。
您可以通过手动将一部分行传递到read_csv
构造函数来实现所需的结果:
import pandas as pd
import io
from itertools import islice
with open("file.csv", "r") as f:
dfs = []
while True:
table_name = f.readline().strip()
if table_name and ',' not in table_name:
data = ''.join(islice(f, 3)).strip()
table_df = pd.read_csv(io.StringIO(data), sep=',', header=None)
dfs.append([table_name, table_df])
else:
break
# check results
for t_name, df in dfs:
print('---', t_name)
print(df)
示例输出:
--- a
0 1
0 1 100
1 2 200
2 3 300
--- b
0 1 2
0 1 100 200
1 2 200 300
2 3 300 400
答案 1 :(得分:1)
使用Python标准库中的csv
模块,并使用send
指示生成函数所需的行数:
import csv
import pandas as pd
def csvreader(filename):
with open(filename) as csvfile:
reader = csv.DictReader(csvfile)
count = yield
while True:
rows = []
for n,row in enumerate(reader):
rows.append(row)
if n == count:
break
count = yield(pd.DataFrame(rows))
testfile.csv:
i, j, k
1, 2, 4
2, 4, 8
3, 6, 12
4, 8, 16
. . .
设置发电机
x = csvreader(s)
next(x)
请求后2行:
x.send(2)
#returned DataFrame
i j k
0 1 2 4
1 2 4 8
请求下3行:
x.send(3)
#returned DataFrame
i j k
0 3 6 12
1 4 8 16
2 5 10 20
请注意,索引每次都会重新开始。可以通过指定一列作为索引来解决此问题(如果需要,可以在每行中添加一个运行计数器):
count = yield(pd.DataFrame(rows), index=<some column name>)
答案 2 :(得分:0)
不知道为什么我以前没有想到这个。
设置iterator=True
将在csv文件上返回一个迭代器。然后使用get_chunk()
选择要读取的行数:
reader = pd.read_csv(f, iterator=True)
reader.get_chunk(2)
i j k
returns -> 0 1 2 4
1 2 4 8
reader.get_chunk(3)
i j k
2 3 6 12
returns -> 3 4 8 16
4 5 10 20