使用pandas编写单个CSV标题

6

我正在将数据解析成列表,并使用pandas进行框架化并写入CSV文件。首先,我的数据被带入一个集合中,其中invnamedate都是具有许多条目的列表。然后,我使用concat将我遍历过的每个数据集的迭代连接到CSV文件中,如下所示:

counter = True
data = {'Invention': inv, 'Inventor': name, 'Date': date}

if counter is True:
  df = pd.DataFrame(data)
  df = df[['Invetion', 'Inventor', 'Date']]

else:
  df = pd.concat([df, pd.DataFrame(data)])
  df = df[['Invention', 'Inventor', 'Date']]

  with open('./new.csv', 'a', encoding = utf-8) as f:
    if counter is True:
      df.to_csv(f, index = False, header = True)
    else:
      df.to_csv(f, index = False, header = False)

counter = False

计数器 = True 的语句位于我的迭代循环之外,用于解析所有数据,因此它不会每次都被覆盖。
这意味着它仅通过我的数据运行一次,以抓取第一个 df 集合,然后在其后连接。问题在于,即使计数器仅为 True 一次并且对于 df 的第一个 if 语句有效,但它对于我的写入文件却无效。
问题是标题总是一遍又一遍地被写入,而与计数器只为 True 一次的事实无关。 当我将 header = False 与计数器为 True 时交换,则永远不会写入标题。
我认为这是由于 df 的连接方式某种程度上保留了标题,但除此之外我无法找出逻辑错误。
也许还有其他方法可以将标题写入同一 CSV 文件,只写入一次吗?

你代码的第一行是 counter = True。你必须确保它在循环之外,否则每次循环时 counter 都会被设置为 True。 - Tom Lynch
是的,这绝对超出了我的循环范围,我没有提到。我会更新这个事实。 - HelloToEarth
3个回答

8

没有看到代码的其余部分,很难确定出现了什么问题。我已经编写了一些测试数据和逻辑,可以根据您的需求进行调整。

请尝试这样做:

import pandas as pd

early_inventions = ['wheel', 'fire', 'bronze']
later_inventions = ['automobile', 'computer', 'rocket']

early_names = ['a', 'b', 'c']
later_names = ['z', 'y', 'x']

early_dates = ['2000-01-01', '2001-10-01', '2002-03-10']
later_dates = ['2010-01-28', '2011-10-10', '2012-12-31']

early_data = {'Invention': early_inventions,
    'Inventor': early_names,
    'Date': early_dates}

later_data = {'Invention': later_inventions,
    'Inventor': later_names,
    'Date': later_dates}

datasets = [early_data, later_data]

columns = ['Invention', 'Inventor', 'Date']
header = True
for dataset in datasets:
    df = pd.DataFrame(dataset)
    df = df[columns]
    mode = 'w' if header else 'a'
    df.to_csv('./new.csv', encoding='utf-8', mode=mode, header=header, index=False)
    header = False

或者,您可以在循环中连接所有数据,并在最后写出数据框:

df = pd.DataFrame(columns=columns)
for dataset in datasets:
    df = pd.concat([df, pd.DataFrame(dataset)])
    df = df[columns]
df.to_csv('./new.csv', encoding='utf-8', index=False)

如果您的代码无法符合此API的要求,您可以完全不写to_csv中的标题。如果输出文件不存在,则可以先检测它是否存在并将标题写入其中:

import os

fn = './new.csv'
if not os.path.exists(fn):
    with open(fn, mode='w', encoding='utf-8') as f:
        f.write(','.join(columns) + '\n')
# Now append the dataframe without a header
df.to_csv(fn, encoding='utf-8', mode='a', header=False, index=False)

是的,使用代码片段确实有些困难,因为这个脚本有点大。你的代码问题在于它假设早期发明和后期发明同时存在,因此你可以根据累积数据集将它们转换为DataFrame。然而,我的脚本一次只解析其中一个列表 - 其中我的数据(上面命名为data)会在大型for循环的每次迭代中更改。难道没有一种方法可以简单地创建一个长字符串列表(例如你的“columns”),并在其他数据之前只写一次吗?我的代码在此之外都能正常工作。 - HelloToEarth
是的,您可以单独编写标题行,然后将每个数据框附加到文件中而不包括标题。 - Tom Lynch
你能为我提供伪代码吗?这实际上是我最初遇到的困难。 - HelloToEarth

0
我发现了同样的问题。如果数据框已经完成且不需要超出任何教程之外的操作,那么Pandas的dataframe to csv就可以正常工作。
但是,如果我们的程序正在生成结果并将它们附加到数据框中,似乎我们会遇到重复标题写入问题
为了解决这个问题,请考虑以下函数:
def write_data_frame_to_csv_2(dict, path, header_list):
    df = pd.DataFrame.from_dict(data=dict, orient='index')
    filename = os.path.join(path, 'results_with_header.csv')
    if os.path.isfile(filename):
        mode = 'a'
        header = 0
    else:
        mode = 'w'
        header = header_list

    with open(filename, mode=mode) as f:
        df.to_csv(f, header=header, index_label='model')

如果文件不存在,我们使用写入模式,并且标题等于标题列表。当这个条件为假且文件存在时,我们使用追加模式并将标题更改为0。
该函数接收一个简单的字典作为参数,我在这种情况下使用了:
model = { 'model_name':{'acc':0.9,
                    'loss':0.3,
                    'tp':840,
                    'tn':450}

      }

在IPython控制台中多次使用该函数形式会产生预期的结果:
write_data_frame_to_csv_2(model, './', header_list)

生成的 CSV 文件:

model,acc,loss,tp,tn
model_name,0.9,0.3,840,450
model_name,0.9,0.3,840,450
model_name,0.9,0.3,840,450
model_name,0.9,0.3,840,450

如果有帮助,请告诉我。 编程愉快!


0

如果您正在使用索引迭代API调用以将数据添加到CSV文件中,请在设置标题属性之前添加此检查。

if i > 0:
        dataset.to_csv('file_name.csv',index=False, mode='a', header=False)
    else:
        dataset.to_csv('file_name.csv',index=False, mode='a', header=True)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接