【问题标题】:Reformat CSV file using Python and Pandas, (AWK)?使用 Python 和 Pandas (AWK) 重新格式化 CSV 文件?
【发布时间】:2015-11-09 15:05:05
【问题描述】:

我有一个如下所示的 CSV 文件:

Names, Size, State, time1,   time2,       
S1,    22,   MD  , 0.022, ,  523.324
S2,    22,   MD  , 4.32,  , 342.54 
S3,    22,   MD  , 3.54,  ,   0.32
S4,    22,   MD  , 4.32,  ,  0.54  
S1,    33,   MD  , 5.32,  ,  0.43
S2,    33,   MD  , 11.54, ,  0.65
S3,    33,   MD  , 22.5,  ,  0.324
S4,    33,   MD  , 45.89  ,  0.32
S1,    44,  MD  , 3.53   ,  3.32
S2,    44,  MD  ,  4.5   ,  0.322
S3,    44,  MD  , 43.65  ,   45.78
S4,    44,   MD,   43.54 , 0.321

我不关心 state

我的输出文件需要如下所示:

 Size ,   S1` ,    S2  ,   S3  ,   S4   

  22   ,  0.022 ,  4.32 ,  45.89 ,  4.32

  33  ,  5.32,    11.54 ,  22.5,   45.89, 

  44  ,  3.53,    4.5,     43.65,  43.54

        3 values, 3 values, 3,values, 3 values

如您所见,输出文件包含不同的标头,这些标头是第一个 csv 文件中的值。 csv 文件按 Size 列排序。换句话说,我想知道哪个时间与每个文件 (S1,S2,S3,S4) 的大小相关联。列的顺序也发生了变化。现在输出文件中第一列中的大小列。最后一行还表示每列中值的总数。

到目前为止我的代码:

import pandas as pd
import numpy as np
import csv

df=pd.read_csv(r'C:\Users\testuser\Desktop\file.csv',usecols=[0,1,2,3,4])
df.columns=pd.MultiIndex.from_tuples(zip(['Names','FileSize','x','y','z'],df.columns)) *#add column headers... (this did not do it correctly)*
df_out=df.groupby('Names','FileSize').count().reset_index() *#suppose to print distinct values*
df_out.to_csv('processed_data_out.csv', columns['Names','FileSize','x','y','z'], header=False,index=False)

我知道我没有使用最后一列 time2,因为我不知道如何添加它以便用户知道什么时间(时间 1 和时间 2)与大小相关联。

【问题讨论】:

    标签: python-2.7 csv pandas awk


    【解决方案1】:

    awk 这里不需要,因为你已经在使用 python,我会继续使用 python:

    convert.py:

    import csv 
    import sys
    
    filename = sys.argv[1]
    
    with open(filename, 'rb') as csvfile:
        reader = csv.reader(csvfile)
        data = {}
        next(reader, None)  # skip the headers
        for row in reader:
            size = int(row[1])
            time1 = float(row[3])
    
            if not size in data:
                data[size] = []
    
            data[size].append(time1)
    
    
    writer = csv.writer(sys.stdout)
    writer.writerow(["Size","S1","S2","S3","S4"])
    for item in data:
        row = [item]
        row.extend(data[item])
        writer.writerow(row)
    

    这样称呼它:

    python convert.py C:\Users\testuser\Desktop\file.csv
    

    输出:

    Size,S1,S2,S3,S4
    33,5.32,11.54,22.5,45.89
    44,3.53,4.5,43.65,43.54
    22,0.022,4.32,3.54,4.32
    

    顺便说一句,awk 解决方案可能如下所示:

    awk -F'[, ]*' '
        NR>1{
            a[$2]=a[$2]","$4
        }
        END{
            for(i in a){
                print i""a[i]
            }
        }' input.csv
    

    【讨论】:

    • 这只会打印大小列,没有任何重复
    • 无法重现。您的输入文件名为input.csv(或者您更改了它)?
    • 我已经修改了代码,现在你可以通过命令行传递文件名了。
    • filename= sys.argv[1] 给我一个超出范围的错误
    • 你需要传递文件名!
    【解决方案2】:

    求救

    awk -F, -f table.awk
    

    在哪里

    $ cat table.awk
    
        NR == 1 {
                h = $1           # save header
                next
        }
    
        NR == 2 {
                p = $2           # to match blocks
                v = $2           # value accumulator
        }
    
        p == $2 {                # we're in the same block
                v = v FS $4      # start accumulate values
                if (h != "") {   # if we're not done with header
                        h = h FS $1    # accumulate header values
                }
        }
    
        p != $2 {                # we're in a new block
                if (h != "") {   # if not printed yet, print header
                        print h
                        h = ""   # and reset
                }
                print v          # print values
                p = $2           # set new block indicator
                v = $2 FS $4     # accumulate values
        }
    
        END {
                print v          # for the final block print values
        }
    

    测试

    awk -F, -f table.awk << !
    > Names, Size, State, time1,   time2,
    > S1,    22,   MD  , 0.022, ,  523.324
    > S2,    22,   MD  , 4.32,  , 342.54
    > S3,    22,   MD  , 3.54,  ,   0.32
    > S4,    22,   MD  , 4.32,  ,  0.54
    > S1,    33,   MD  , 5.32,  ,  0.43
    > S2,    33,   MD  , 11.54, ,  0.65
    > S3,    33,   MD  , 22.5,  ,  0.324
    > S4,    33,   MD  , 45.89  ,  0.32
    > S1,    44,  MD  , 3.53   ,  3.32
    > S2,    44,  MD  ,  4.5   ,  0.322
    > S3,    44,  MD  , 43.65  ,   45.78
    > S4,    44,   MD,   43.54 , 0.321
    > !
    Names,S1,S2,S3,S4
    22, 0.022, 4.32, 3.54, 4.32
    33, 5.32, 11.54, 22.5, 45.89
    44, 3.53   ,  4.5   , 43.65  ,   43.54
    

    【讨论】:

    • 这会打印状态列
    • 不这么认为。刚刚根据您的输入数据添加了一个测试输出。请注意,要打印的代码中没有对第三个字段的引用。也许您的示例输入和您的测试输入不同?
    • @karakfa this 怎么样?
    • @hek2mgl 短得多,但我认为失去了订单。使用排序可能没问题。
    • @karakfa 你是对的。 gawk 为此目的提供 PROCINFO["sorted_in"]
    【解决方案3】:

    我喜欢这两种 awk 解决方案背后的想法,但对于那些想要一种不那么简洁且看起来更像其他脚本解决方案的中间风格的 awk 的人,请考虑一下:

    BEGIN { 
      while ("cat data1" | getline) {
        if ($0 ~ /S[1-4]/) {
          split($0,temp,/[ ,]+/)
          oline[temp[2]] = oline[temp[2]] " ,  " temp[4]
        }
      }
      print "Size ,   S1 ,    S2  ,   S3  ,   S4"
      for (i in oline) print i oline[i]
    }
    
    
    
    OUTPUT:
    Size ,   S1 ,    S2  ,   S3  ,   S4
    22 ,  0.022 ,  4.32 ,  3.54 ,  4.32
    33 ,  5.32 ,  11.54 ,  22.5 ,  45.89
    44 ,  3.53 ,  4.5 ,  43.65 ,  43.54
    

    如果数据的行顺序不是很好,可以使用“sort -nk2 -k1”代替“cat”,以确保它对行重新排序具有鲁棒性。仍假定 S1-S4 行命名。

    【讨论】:

      猜你喜欢
      • 2016-10-04
      • 2015-12-07
      • 1970-01-01
      • 1970-01-01
      • 2020-07-19
      • 1970-01-01
      • 2020-10-28
      • 2012-06-07
      • 1970-01-01
      相关资源
      最近更新 更多