【问题标题】:How to remove a subcolumn from a nested-csv file?如何从嵌套 csv 文件中删除子列?
【发布时间】:2016-05-08 01:32:03
【问题描述】:

给定一个空格分隔的文件:

0.0 1:0.000000 2:1.000000 3:0.000000 4:0.000000 5:1.000000 6:0.000000 7:1.000000 8:1.000000 9:1.000000 10:1.000000 11:1.000000 12:1.000000 13:1.000000 14:1.000000 15:0.919033 16:1.000000 17:1.000000 18:1.000000 19:1.000000 20:0.000000 21:0.037771
0.0 1:0.000000 2:1.000000 3:0.000000 4:0.000000 5:1.000000 6:0.000000 7:1.000000 8:0.800000 9:0.666667 10:1.000000 11:0.800000 12:0.666667 13:1.000000 14:0.875000 15:0.874574 16:0.848662 17:0.901802 18:0.938795 19:0.903077 20:0.333332 21:0.196682
0.0 1:1.098612 2:1.000000 3:1.000000 4:0.000000 5:1.000000 6:0.000000 7:1.000000 8:0.800000 9:0.500000 10:0.000000 11:0.800000 12:0.500000 13:0.000000 14:0.909091 15:0.780985 16:0.792052 17:0.865396 18:0.863982 19:0.832962 20:0.000000 21:0.069470
0.0 1:0.000000 2:1.000000 3:0.000000 4:0.000000 5:1.000000 6:0.000000 7:1.000000 8:0.923077 9:0.909091 10:0.888889 11:0.923077 12:0.909091 13:0.888889 14:0.943396 15:0.923562 16:0.923871 17:0.949357 18:0.950790 19:0.944919 20:0.142857 21:0.140054

第一列都是0.0,我们想把第一列扔掉。然后对于每一列,都有一个冒号将键与其值分开。而目标只是保值。

我可以在python这样做:

with io.open(infile, 'r') as fin:
    for line in fin:
        line = line.split()[1:]
        line = '\t'.join([i.split(':')[1] for i in line])
        print line

[出]:

0.000000    1.000000    0.000000    0.000000    1.000000    0.000000    1.000000    1.000000    1.000000    1.000000    1.0000001.000000    1.000000    1.000000    0.919033    1.000000    1.000000    1.000000    1.000000    0.000000    0.037771
0.000000    1.000000    0.000000    0.000000    1.000000    0.000000    1.000000    0.800000    0.666667    1.000000    0.8000000.666667    1.000000    0.875000    0.874574    0.848662    0.901802    0.938795    0.903077    0.333332    0.196682
1.098612    1.000000    1.000000    0.000000    1.000000    0.000000    1.000000    0.800000    0.500000    0.000000    0.8000000.500000    0.000000    0.909091    0.780985    0.792052    0.865396    0.863982    0.832962    0.000000    0.069470
0.000000    1.000000    0.000000    0.000000    1.000000    0.000000    1.000000    0.923077    0.909091    0.888889    0.9230770.909091    0.888889    0.943396    0.923562    0.923871    0.949357    0.950790    0.944919    0.142857    0.140054

但是在 unix 命令行上怎么可能呢?(可能是 sedawkperl -c 甚至 python -c 或其他任何东西)想象它是一个大文件,所以请不要将整个文件加载到内存中,除非有经济原因。

【问题讨论】:

    标签: python perl csv awk sed


    【解决方案1】:

    使用 GNU sed:

    sed 's/^0.0 //;s/[0-9]\+:\([0-9.]\+\)/\1/g' file
    

    输出:

    0.000000 1.000000 0.000000 0.000000 1.000000 0.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.919033 1.000000 1.000000 1.000000 1.000000 0.000000 0.037771 0.000000 1.000000 0.000000 0.000000 1.000000 0.000000 1.000000 0.800000 0.666667 1.000000 0.800000 0.666667 1.000000 0.875000 0.874574 0.848662 0.901802 0.938795 0.903077 0.333332 0.196682 1.098612 1.000000 1.000000 0.000000 1.000000 0.000000 1.000000 0.800000 0.500000 0.000000 0.800000 0.500000 0.000000 0.909091 0.780985 0.792052 0.865396 0.863982 0.832962 0.000000 0.069470 0.000000 1.000000 0.000000 0.000000 1.000000 0.000000 1.000000 0.923077 0.909091 0.888889 0.923077 0.909091 0.888889 0.943396 0.923562 0.923871 0.949357 0.950790 0.944919 0.142857 0.140054

    如果您想“就地”编辑文件,请添加 sed 的选项 -i


    两个用;分隔的sed脚本:

    s/^0.0 //:从行首 (^) 搜索 0.0,后跟一个空格,然后将其替换为空

    s/[0-9]\+:\([0-9.]\+\)/\1/g:从09 范围内搜索任何至少一个(+) 字符,然后是:,然后在0 范围内搜索至少一个(+) 字符到9. 并用圆括号中的匹配部分替换它。 \1 是圆括号中匹配部分的反向引用。 g 表示全局将替换应用于正则表达式的所有匹配项,而不仅仅是第一个。 sed 需要使用 \ 转义特殊字符(here: +())。

    短版:

    sed 's/^0.0 //;s/[0-9]\+://g' file
    

    见:The Stack Overflow Regular Expressions FAQ

    【讨论】:

    • 想解释一下正则表达式吗?
    【解决方案2】:

    awk 来救援!

    $ awk '{gsub("[^ ]*:","");sub("[^ ]* ","")}1' file 
    
    0.000000 1.000000 0.000000 0.000000 1.000000 0.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.919033 1.000000 1.000000 1.000000 1.000000 0.000000 0.037771
    0.000000 1.000000 0.000000 0.000000 1.000000 0.000000 1.000000 0.800000 0.666667 1.000000 0.800000 0.666667 1.000000 0.875000 0.874574 0.848662 0.901802 0.938795 0.903077 0.333332 0.196682
    1.098612 1.000000 1.000000 0.000000 1.000000 0.000000 1.000000 0.800000 0.500000 0.000000 0.800000 0.500000 0.000000 0.909091 0.780985 0.792052 0.865396 0.863982 0.832962 0.000000 0.069470
    0.000000 1.000000 0.000000 0.000000 1.000000 0.000000 1.000000 0.923077 0.909091 0.888889 0.923077 0.909091 0.888889 0.943396 0.923562 0.923871 0.949357 0.950790 0.944919 0.142857 0.140054
    

    【讨论】:

      【解决方案3】:

      awk 可以做到:

      // {
          for(i=2; i<=NF; i++)
          {
              split($i, array, ":")
              printf("%s\t", array[2])
          }
          printf("\n")
      }
      

      解释// 表示“对于每一行”(实际上,它匹配所有可能的字符序列),for 每个字段从2nd 到最后一个(@987654326 @)、split : 上的 ith 字段并将每个部分存储在 array (从 1 开始,所以 array[2] 是第二部分)和 printf 它。在每一行的末尾,打印一个换行符。

      编辑

      这是我的第一个答案,但我跳过了删除每一列的其他部分。

      你可以使用cut命令:例如,如果你只需要删除第一列,你可以写

      cut -c2- yourfile
      

      解释-c 让您选择要保留的列,2- 表示“从第二个开始”。

      【讨论】:

        【解决方案4】:

        为什么不使用该模块:

        use Text::CSV;
        

        它已经提供了将 CSV 文件轻松解析为结构的功能,并且还提供了将结构解析为 CSV 文件的另一种方式。

        然后您可以选择要保留或删除的列。

        【讨论】:

        • 我认为这可以通过一个例子得到很大的改进 - 我认为给定数据集不需要Text::CSV,并且是解析此文件的一种重量级方法。
        【解决方案5】:

        使用 perl 很容易:

        perl -ne 'print join ( "\t", m/:([\d\.]+)/g ),"\n"' file_to_parse
        

        这个:

        • 逐行迭代(-n 将其包装在 while ( &lt;&gt; ) { 循环中)
        • 使用正则表达式m/:([\d\.]+)/g 提取: 之后的数值(并重复此操作)。我假设 digits and . 但实际上如果“任何非空白”都可以(如您的示例中所示),您可能只需执行 m/:(\S+)/g
        • 您的第一个字段不包含 :,因此省略了它
        • 打印,制表符分隔

        输出:

        0.000000    1.000000    0.000000    0.000000    1.000000    0.000000    1.000000    1.000000    1.000000    1.000000    1.000000    1.000000    1.000000    1.000000    0.919033    1.000000    1.000000    1.000000    1.000000    0.000000    0.037771
        0.000000    1.000000    0.000000    0.000000    1.000000    0.000000    1.000000    0.800000    0.666667    1.000000    0.800000    0.666667    1.000000    0.875000    0.874574    0.848662    0.901802    0.938795    0.903077    0.333332    0.196682
        1.098612    1.000000    1.000000    0.000000    1.000000    0.000000    1.000000    0.800000    0.500000    0.000000    0.800000    0.500000    0.000000    0.909091    0.780985    0.792052    0.865396    0.863982    0.832962    0.000000    0.069470
        0.000000    1.000000    0.000000    0.000000    1.000000    0.000000    1.000000    0.923077    0.909091    0.888889    0.923077    0.909091    0.888889    0.943396    0.923562    0.923871    0.949357    0.950790    0.944919    0.142857    0.140054
        

        【讨论】:

          猜你喜欢
          • 2019-11-30
          • 1970-01-01
          • 1970-01-01
          • 2014-03-26
          • 1970-01-01
          • 2022-11-15
          • 1970-01-01
          • 2011-11-27
          • 1970-01-01
          相关资源
          最近更新 更多