【问题标题】:Writing single CSV header with pandas用 pandas 编写单个 CSV 标头
【发布时间】:2018-06-11 16:49:24
【问题描述】:

我正在将数据解析为列表,并使用 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

counter = True 语句位于我正在解析的所有数据的迭代循环之外,因此它不会每次都被覆盖。

所以这意味着它只在我的数据中运行 一次 以获取第一个 df 集,然后将其连接起来。问题是,即使 counter 仅在第一轮为 True 并且适用于我的第一个 if-statement for df,但它不适用于我写入文件。

发生的情况是,标题被一遍又一遍地写入 - 不管计数器只为 True 一次这一事实。当我将 header = False 换成 counter 为 True 时,它​​永远不会写入 header。

我认为这是因为 df 以某种方式连接到标题上,但除此之外我无法弄清楚逻辑错误。

是否有另一种方法也可以将标题写入同一个 CSV 文件一次且仅一次?

【问题讨论】:

  • 代码的第一行是 counter = True。你必须确保它在循环之外,否则每次循环都会将计数器设置为 True。
  • 是的,这绝对在我没有提到的循环之外。我会更新这个事实。

标签: python pandas csv dataframe header


【解决方案1】:

如果不查看其余代码,很难判断可能出了什么问题。我开发了一些有效的测试数据和逻辑;您可以对其进行调整以满足您的需求。

请试试这个:

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)

【讨论】:

  • 是的,使用 sn-p 很困难,因为这个脚本有点大。您的代码的问题在于,它假定 early_inventions 和 later_inventions 同时存在,因此您可以根据 datasets 对它们进行 DataFrame。但是,我的脚本一次解析其中一个列表 - 其中 my 数据(上面命名的数据)随着大型 for 循环中的每次迭代而变化。是不是有什么方法可以简单地创建一长串字符串(例如你的“列”),然后在其他数据之前写一次?我的代码在此之外工作正常。
  • 是的,您可以单独编写标题行,然后将每个数据帧附加到不带标题的文件中。
  • 你能给我提供一个伪代码吗?这实际上是我最初的挣扎。
【解决方案2】:

我发现了同样的问题。如果数据框已完成并且无需执行任何教程之外的任何操作,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')

如果文件不存在我们使用写模式并且header等于header list。当这是 false 并且 文件存在 我们使用 append 并且 header 更改为 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

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

【讨论】:

    【解决方案3】:

    如果您使用索引来迭代 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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-02-20
      • 2017-02-24
      • 1970-01-01
      • 2015-10-18
      相关资源
      最近更新 更多