将包含多个表格的CSV文件拆分为不同的pandas数据帧(Python)
将包含多个表格的CSV文件拆分为不同的pandas数据帧(Python)
我有多个CSV文件,内部格式化为多个由换行符分隔的表格。
示例:
Technology C_inv [MCHF/y] C_maint [MCHF/y] NUCLEAR 70.308020 33.374568 HYDRO_DAM_EXISTING 0.000000 195.051200 HYDRO_DAM 67.717942 1.271600 HYDRO_RIVER_EXISTING 0.000000 204.820000 IND_BOILER_OIL 2.053610 0.532362 IND_BOILER_COAL 4.179935 1.081855 IND_BOILER_WASTE 11.010126 2.849652 DEC_HP_ELEC 554.174644 320.791276 DEC_THERMAL_HP_GAS 77.077291 33.717477 DEC_BOILER_GAS 105.586089 41.161335 DEC_BOILER_OIL 33.514266 25.948450 H2_FROM_GAS 145.185290 59.178082 PYROLYSIS 132.200818 112.392123 Storage technology C_inv [MCHF/y] C_maint [MCHF/y] HYDRO_STORAGE 0.000000 0.000000 Resource C_op [MCHF/y] ELECTRICITY 1174.452848 GASOLINE 702.000000 DIESEL 96.390000 OIL 267.787558 NG 1648.527242 WOOD 592.110000 COAL 84.504083 URANIUM 18.277626 WASTE 0.000000
我所有的CSV文件都有不同的子表格名称,但数量较少,如果需要的话可以手动输入它们以检测。
另一个问题是许多标题包含空格(例如 "Storage Technology"),这被pandas读取为2列。
我最初尝试直接使用pandas和手动拆分,但是参数on_bad_lines='skip'
可以避免错误,但也会跳过有用的行:
Cost_bd = pd.read_csv(f"{Directory}/cost_breakdown.csv",on_bad_lines='skip',delim_whitespace=True).dropna(axis=1,how='all') colnames=['Technnolgy', 'C_inv[MCHF/y]', 'C_maint[MCHF/y]'] Cost_bd.columns = colnames
我认为最好的方法可能是扫描.txt
文件并进行拆分,但我不确定如何以最佳方式做到这一点。
我还尝试使用此链接中提供的解决方案:
import csv from os.path import dirname # 获取路径的父文件夹 from os.path import join # 连接路径 table_names = ["Technology", "Storage technology", "Resource"] df = pd.read_csv(f"{Directory}/cost_breakdown.csv", header=None, names=range(3)) groups = df[0].isin(table_names).cumsum() tables = {g.iloc[0,0]: g.iloc[1:] for k,g in df.groupby(groups)}
但它不起作用:
tables.keys()= dict_keys(['Technology\tC_inv [MCHF/y]\tC_maint [MCHF/y]'])
编辑:基于@Rabinzel的最终解决方案:
import re def make_df(group,dict_of_dfs): header, data = re.split(r'\t',group[0]), list(map(str.split, group[1:])) if len(header) != len(data[0]): # 如果缺少列列表,取前一个 header = header + dict_of_dfs[list(dict_of_dfs.keys())[0]].columns.tolist()[1:] dict_of_dfs[header[0]] = pd.DataFrame(data, columns=header) return dict_of_dfs def Read_csv_as_df(path, file_name): with open(path+file_name) as f: dict_of_dfs = {} group = [] for line in f: if line!='\n': group.append(line.strip()) else: print(dict_of_dfs) dict_of_dfs = make_df(group,dict_of_dfs) group = [] dict_of_dfs = make_df(group,dict_of_dfs) return dict_of_dfs
问题:如何将包含多个表格的CSV文件拆分成不同的pandas数据框?
原因:CSV文件中包含多个表格,每个表格之间由换行符分隔,且每个表格的列名中可能包含空格。需要将每个表格提取出来,并构建成相应的pandas数据框。
解决方法:
1. 遍历CSV文件的每一行,将每个表格的行按照换行符分隔,添加到一个列表中。
2. 使用正则表达式的re.split函数,只在列名中存在两个或更多空格时进行分割,以解决列名中含有空格的问题。
3. 将不同的数据框保存在一个字典中,其中键是每个数据框的列名的第一个元素。
4. 使用with open打开CSV文件,使用group列表存储每个表格的行数据,当遇到换行符时,将group列表中的数据构建成一个数据框,并添加到字典中。
5. 遍历字典,打印出每个数据框的列名和数据。
代码如下:
import re import pandas as pd def make_df(group): header, data = re.split(r'\s\s+',group[0]), list(map(str.split, group[1:])) dict_of_dfs[header[0]] = pd.DataFrame(data, columns=header) with open('your_csv_file.csv') as f: dict_of_dfs = {} group = [] for line in f: if line!='\n': group.append(line.strip()) else: make_df(group) group = [] make_df(group) for key, value in dict_of_dfs.items(): print(f"{key=}\ndf:\n{value}\n---------------------")
输出结果示例:
key='Technology' df: Technology C_inv [MCHF/y] C_maint [MCHF/y] 0 NUCLEAR 70.308020 33.374568 1 HYDRO_DAM_EXISTING 0.000000 195.051200 2 HYDRO_DAM 67.717942 1.271600 3 HYDRO_RIVER_EXISTING 0.000000 204.820000 4 IND_BOILER_OIL 2.053610 0.532362 5 IND_BOILER_COAL 4.179935 1.081855 6 IND_BOILER_WASTE 11.010126 2.849652 7 DEC_HP_ELEC 554.174644 320.791276 8 DEC_THERMAL_HP_GAS 77.077291 33.717477 9 DEC_BOILER_GAS 105.586089 41.161335 10 DEC_BOILER_OIL 33.514266 25.948450 11 H2_FROM_GAS 145.185290 59.178082 12 PYROLYSIS 132.200818 112.392123 --------------------- key='Storage technology' df: Storage technology C_inv [MCHF/y] C_maint [MCHF/y] 0 HYDRO_STORAGE 0.000000 0.000000 --------------------- key='Resource' df: Resource C_op [MCHF/y] 0 ELECTRICITY 1174.452848 1 GASOLINE 702.000000 2 DIESEL 96.390000 3 OIL 267.787558 4 NG 1648.527242 5 WOOD 592.110000 6 COAL 84.504083 7 URANIUM 18.277626 8 WASTE 0.000000 ---------------------
在make_df函数中,可以将key设置为header[0],以使键名为表格名。
感谢你的快速回答!我最终实现了一个解决方案,但你的方法更简洁。但是我尝试运行你的代码时返回了一个错误:ValueError: 1 columns passed, passed data had 3 columns。你知道问题出在哪里吗?
我猜测你的数据中有一些列(我认为是列名),在元素之间没有两个或更多的空格,因此它们不会被分割。Pandas期望得到一个包含3个列名(3列)的列表,但只得到了一个包含3个名称的大字符串(1列)。
尽管这是我在这里发布的相同文件。我该如何解决?
你可以再次运行我的代码,并在for line in f的后面直接添加print(line)。这样我们就可以看到代码在文件的哪一行抛出错误。
... PYROLYSIS 132.200818 112.392123 Right after: AssertionError: 1 columns passed, passed data had 2 columns. 所以错误出现在第二个表格。
好的,我仔细查看了你提供的示例数据的方式。我将其保存为文本文件,发现"Storage technology"和"C_inv [MCHF/y]"之间有两个空格,但是你的数据中可能是用制表符分隔的。尝试将re.split(r'\s\s+',group[0])中的\s\s+更改为\t,可能会有帮助。
成功了!我还必须将make_df(group)更改为make_df(group,dict_of_dfs)才能使其作为函数正常工作。非常感谢!
很好,很高兴听到!你可以通过接受这个答案来感谢我 🙂
已完成!对不起,我是StackOverflow的新手。我在对我的帖子进行了一些修改后,将最新版本作为编辑添加了一些微小的更改。