【问题标题】:Transpose CSV data with awk (pivot transformation)使用 awk 转置 CSV 数据(枢轴转换)
【发布时间】:2014-07-08 23:45:23
【问题描述】:

我的 CSV 数据如下所示:

Indicator;Country;Value
no_of_people;USA;500
no_of_people;Germany;300
no_of_people;France;200
area_in_km;USA;18
area_in_km;Germany;16
area_in_km;France;17
proportion_males;USA;5.3
proportion_males;Germany;7.9
proportion_males;France;2.4

我希望我的数据如下所示:

Country;no_of_people;area_in_km;proportion_males
USA;500;18;5.3
Germany;300;16;7.9
France;200;17;2.4

指标和国家比这里列出的更多。

相当大的文件(行数为 5 位数)。 环顾四周寻找一些转置线程,但没有什么符合我的情况(而且我对 awk 还是很陌生,所以我无法更改找到的代码以适合我的数据)。

感谢您的帮助。 问候 广告

【问题讨论】:

    标签: bash csv awk pivot-table transpose


    【解决方案1】:

    使用awk并保持输出顺序:

    awk -F\; '
    NR>1 { 
        if(!($1 in indicators)) { indicator[++types] = $1 }; indicators[$1]++  
        if(!($2 in countries)) { country[++num] = $2 }; countries[$2]++
        map[$1,$2] = $3 
    }
    END {
        printf "%s;" ,"Country";
        for(ind=1; ind<=types; ind++) {
            printf "%s%s", sep, indicator[ind]; 
            sep = ";"
        }
        print "";
        for(coun=1; coun<=num; coun++) {
            printf "%s", country[coun]
            for(val=1; val<=types; val++) {
                printf "%s%s", sep, map[indicator[val], country[coun]];
            }
            print ""
        }
    }' file
    Country;no_of_people;area_in_km;proportion_males
    USA;500;18;5.3
    Germany;300;16;7.9
    France;200;17;2.4
    

    【讨论】:

      【解决方案2】:

      如果Ind字段的数量是固定的,你可以这样做:

      awk 'BEGIN{FS=OFS=";"}
           {a[$2,$1]=$3; count[$2]}
           END {for (i in count) print i, a[i,"Ind1"], a[i, "Ind2"], a[i, "Ind3"]}' file
      

      说明

      • BEGIN{FS=OFS=";"} 设置输入输出字段分隔符为分号。
      • {a[$2,$1]=$3; count[$2]} 获取count[] 数组中的国家列表以及a["country","Ind"] 数组中每个Ind 的值。
      • END {for (i in count) print i, a[i,"Ind1"], a[i, "Ind2"], a[i, "Ind3"]} 打印值的摘要。

      输出

      $ awk 'BEGIN{FS=OFS=";"} {a[$2,$1]=$3; count[$2]} END {for (i in count) print i, a[i,"Ind1"], a[i, "Ind2"], a[i, "Ind3"]}' file
      France;200;17;2.4
      Germany;300;16;7.9
      USA;500;18;5.3
      

      更新

      不幸的是,指标的数量不是固定的。而且,他们是 不像“Ind1”、“Ind2”等命名,而只是字符串。我澄清了 我的问题。

      $ awk -v FS=";" '{a[$2,$1]=$3; count[$2]; indic[$1]} END {for (j in indic) printf "%s ", j; printf "\n"; for (i in count) {printf "%s ", i; for (j in indic) printf "%s ", a[i,j]; printf "\n"}}' file
      proportion_males no_of_people area_in_km 
      France 2.4 200 17 
      Germany 7.9 300 16 
      USA 5.3 500 18 
      

      要分隔;,请将每个空格替换为;

      $ awk -v FS=";" '{a[$2,$1]=$3; count[$2]; indic[$1]} END {for (j in indic) printf "%s ", j; printf "\n"; for (i in count) {printf "%s ", i; for (j in indic) printf "%s ", a[i,j]; printf "\n"}}' file | tr ' ' ';'
      proportion_males;no_of_people;area_in_km;
      France;2.4;200;17;
      Germany;7.9;300;16;
      USA;5.3;500;18;
      

      【讨论】:

      • 谢谢。不幸的是,指标的数量不是固定的。此外,它们的名称不像“Ind1”、“Ind2”等,而只是字符串。我澄清了我的问题。
      • 哦,我明白了。然后我们必须跟踪指标。检查我的更新答案!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-25
      • 1970-01-01
      • 1970-01-01
      • 2016-09-07
      相关资源
      最近更新 更多