使用awk转置CSV数据(数据透视转换)

时间:2014-05-20 15:44:47

标签: bash csv awk pivot-table transpose

我的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的新手,所以我无法更改我发现的适合我的数据的代码)。

感谢您的帮助。 问候 广告

2 个答案:

答案 0 :(得分: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[]数组中的国家/地区列表以及Ind数组中每个a["country","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;

答案 1 :(得分: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