将包含多个表格的CSV文件拆分为不同的pandas数据帧(Python)

15 浏览
0 Comments

将包含多个表格的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

0
0 Comments

问题:如何将包含多个表格的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的新手。我在对我的帖子进行了一些修改后,将最新版本作为编辑添加了一些微小的更改。

0