【问题标题】:Remove columns csv files, some of which contain quoted text including commas删除列 csv 文件,其中一些包含带引号的文本,包括逗号
【发布时间】:2018-10-30 17:38:28
【问题描述】:

我有一个包含数百列和 80 行的 csv 文件。我需要从文件中删除前 13 列。 我试过使用:

cut -d, -f1-13 --complement input.csv > output.csv

但问题是第一列中的一个包含带引号的文本,包括逗号,并且 cut 无法处理这种格式。 示例输入:

标头A、标头B、标头C、标头D、标头E、标头F、标头G、标头H A、“B、B”、C、“D、D、D、D”、E、F、G、H A、“B、B”、C、“D、D、D、D”、E、F、G、H A、“B、B”、C、“D、D、D、D”、E、F、G、H

期望的输出:

标头E、标头F、标头G、标头H E、F、G、H E、F、G、H E、F、G、H

在示例中,我在类似条件下使用较少数量的列。理想情况下,该解决方案应该可以扩展到任意数量的列和行(在我的例子中是 13 列和 80 行)。 我曾尝试使用 awk 寻找解决方案,但它们通常包括打印除要删除的列之外的所有列,由于列的数量庞大,这不是一个实用的解决方案。

【问题讨论】:

  • 在 vanilla bash 中没有很好的方法来做到这一点。是否有机会使用包含 csv 解析的语言,例如 python?
  • @Alex Stiff 你怎么知道的?
  • @AlexStiff 我认为提交的两个答案反驳了您的说法。

标签: linux bash csv


【解决方案1】:

考虑到您设定的特定条件,这样的事情会起作用:

grep -oE '(("[^"]+"|[^,]+),?){5}$' input.csv > output.csv

{5} 中的5 被替换为您希望剩余的列数。因此,给定 N 列,其中前 13 列将被省略,该值将是 N - 13

注意: 如果任何引用的列数据本身包含引号,则正则表达式将无法正确匹配,例如"some \"data\" in quotes",虽然可以调整模式以适应这种情况(但它变得相当复杂)。

【讨论】:

  • 谢谢,我今天只能测试您的解决方案并且它有效,即使它比预期的处理速度慢一点。即使我不想让我的脚本过于复杂,我也会尝试测试 python pandas 的建议。
  • 不幸的是,我很难在较大的文件上实现您的解决方案,我无法在编辑器中打开它们以查看总共存在多少列,并且由于引号中的逗号问题。因此,我无法执行您的解决方案所需的 N-13 计算。编辑:我仍然会将您的答案标记为正确,因为它适用于较小的文件。
  • 如果您使用head -n 1 input.csv 提取文件的第一行,即标题行,并计算该行中的列数,该怎么办。您可以使用与上述类似的grep,但不使用{5},或者假设标题不包含引号的更简单版本。整个事情会这样完成:head -n 1 input.csv | grep -oE '[^,]+' | wc -l,返回的结果是列的总数。
  • 感谢您的建议,建议的命令运行良好。
【解决方案2】:

您可以在 python 中使用 pandas 来做到这一点。

为此,您可以编写一个简单的函数来执行以下操作:

  • 将 csv 加载到 pandas 数据帧
  • 删除不需要的列
  • 将所有内容保存回新的 csv 文件或恢复原样。

代码:

import pandas as pd

def remove_columns_from_csv(data_path):
    #loading the file
    data_file = pd.read_csv(data_path)
    data = pd.dateFrame(data_file)

    # Use this list if you want to remove by columns names 
    columns_list = ['first_columns', 'second_column']

    # Use this list if you want to remove by index
    columns_list = [0,1,3] # subselection of columns you want removed
    data = data.drop(columns=columns_list)

    # saving the data back to a csv
    file_name = 'type the file name here'
    data.to_csv(file_name, sep='\t', encoding='utf-8')


# Function call    
datapath = 'C:\\Users\\default_user\\Documents\\csv_filename.csv'
remove_columns_from_csv(datapath)

注意:这里的索引是从零开始的,所以如果你的列号在 csv 中是 1,那么它在 python 中对应的是 0。

【讨论】:

  • 我正在尝试测试您的答案,它是否需要特定的列标题来显示列表,或者我可以使用列号或位置来确定要剪切多少列?
  • 查看pandas文档似乎应该在列表中使用特定的标签,这不是很实用,因为我需要循环命令以应用于具有不同前缀的标题的多个csv文件.我需要一个基于位置/顺序而不是特定标签名称删除列的解决方案。很抱歉,我没有在原始问题中指定这一点。
  • 当然可以根据位置(索引)删除列。您可以简单地使用索引列表更改标签列表。我会更新解决方案,看看对你有没有用。
  • 很抱歉打扰您,我正在尝试实施您的解决方案,但对 python 不是很熟悉。您能否更好地解释如何使用您的脚本?我已经在我的系统上为 python 2 和 3 安装了 pandas,并输入了指示文件的路径,但仍然在终端上收到各种错误。
  • 特别是,我现在收到:ValueError: DataFrame constructor not proper called!
猜你喜欢
  • 1970-01-01
  • 2010-09-27
  • 2016-12-14
  • 2018-07-16
  • 2019-08-30
  • 2020-03-02
  • 2020-03-27
  • 1970-01-01
  • 2023-02-25
相关资源
最近更新 更多