【问题标题】:awk/sed: post-processing of multi-column fille(s)awk/sed:多列填充的后处理
【发布时间】:2021-07-04 20:35:56
【问题描述】:

我正在使用以下 bash 函数,该函数对 CSV 文件进行操作,并为每个 AWK 代码执行对列数据进行一些数学运算,并最终将处理后的 CSV 保存在一个新文件中。

home="$PWD"
# folder with the outputs
rescore="${home}"/rescore 
# folder with the folders to analyse
storage="${home}"/results_bench
cd "${storage}"
# pattern of the csv file located inside each of sub-directory of "${storage}"
str='*str1.csv'

rescore_data2 () {
str_name=$(basename "${str}" .csv)
printf >&2 'Dataset for %s is being rescored...  ' "${str_name}"; sleep 0.1 
mkdir "${rescore}"/"${str_name}"
# Apply the following AWK code for rescoring and final data collecting
while read -r d; do
awk -F', *' -v OFS=', ' '
    FNR==1 {
        path=FILENAME
        sub(/\/[^/]+$/,"",path)
        prefix=suffix=FILENAME
        sub(/_.*/, "", prefix)
        sub(/\/[^\/]+$/, "", suffix); sub(/^.*_/, "", suffix)
        print suffix,"dG(rescored)"
        next
    }
    {
        print $1, sqrt((($3+12)/12)^2+(($2-240)/240)^2)
    }
'  "${d}_"*/${str} > "${rescore}/"${str_name}"/"${d%%_*}".csv"
done < <(find . -maxdepth 1 -type d -name '*_*_*' | awk -F '[_/]' '!seen[$2]++ {print $2}')
}

基本上每个处理后的 CSV 都有以下格式:

#inout CSV located in the folder 10V1_cne_lig12
ID, POP, dG
1, 142, -5.6500 
2, 10, -5.5000
3, 2, -4.9500
4, 150, -4.1200

我的 awk 代码将其转换为 2 列格式(通过在第 2 列和第 3 列应用数学方程式):

# output.csv
lig12, dG(rescored)
1, 0.596625
2, 1.05873
3, 1.11285
4, 0.697402

请注意,第一行中的 lig12 是我的 AWK 代码从包含此 CSV 的 FOLDER 部分中提取的 后缀(用作 csv 的 ID),而 10V1 是 >prefix(定义 csv 的类型)

我需要将我的 AWK 脚本通过管道传输到 sed 或 AWK 之类的东西上,它们将对获得的 output.csv 进行进一步修改 ,它应该被转换为一种行格式,其中包含:后缀 (lig12 ),在输出的第二列中检测到的最小值(这里是 0.596625)以及第一列 (1) 中对应的 ID 号:

lig12, 0.596625 (1)

这是一种 AWK 解决方案,它只为一个 csv 完成这项工作:

 awk -F ', ' ' NR==1 { coltitle=$1 } NR==2 { min=$2; id=$1 } NR>3 && $2<min { min=$2; id=$1 } END { print coltitle FS min" ("id")" }'

它是否可以正确地传送到 rescore_data2() 内的第一个 AWK 代码,该代码应用于我的 bash 函数处理的许多 CSV?所以存储在 ("${rescore}/"${str_name}"/"${d%%_*}".csv") 中的预期输出应该包含行数(每个的 dG(min) CSV) 等于处理的 CSV 的数量。

# expected output for 10 processed CSVs belonged to the prefix 10V1
# currently it does not print dGmin correctly for different CSVs.
    name: 10V1, dG(min)     # header with prefix should be in the top!
    lig199, 0.946749 (1)
    lig211, 0.946749 (1)
    lig278, 0.756155 (2)
    lig40, 0.756155 (2)
    lig576, 0.594778 (1)
    lig619, 0.594778 (1)
    lig697, 0.594778 (1)
    lig800, 0.594778 (1)
    lig868, 0.594778 (1)
    lig868, 0.594778 (1)

【问题讨论】:

    标签: awk sed


    【解决方案1】:

    我提取的 awk 脚本如下(稍作修改):

    awk -F', *' -v OFS=', ' '
        FNR==1 {
            path=FILENAME
            sub(/\/[^/]+$/,"",path)
            prefix=suffix=FILENAME
            sub(/_.*/, "", prefix)
            sub(/\/[^\/]+$/, "", suffix); sub(/^.*_/, "", suffix)
            print suffix,"dG(rescored)"
            next
        }
        {
            print $1, sqrt((($3+12)/12)^2+(($2-240)/240)^2)
        }
    ' 10V1_cne_lig12/foo_str3a.csv
    

    输出如下:

    lig12, dG(rescored)
    1, 0.668396
    2, 1.10082
    3, 1.15263
    4, 0.756198
    

    虽然数值与提供的结果略有不同, 请让我照原样继续。
    然后在 awk 脚本中添加一个修改为:

    awk -F', *' -v OFS=', ' '
        FNR==1 {
            dgmin = ""                              # initialize the min value
            path=FILENAME
            sub(/\/[^/]+$/,"",path)
            prefix=suffix=FILENAME
            sub(/_.*/, "", prefix)
            sub(/\/[^\/]+$/, "", suffix); sub(/^.*_/, "", suffix)
            print suffix,"dG(rescored)"
            next
        }
        {
            dG = sqrt((($3+12)/12)^2+(($2-240)/240)^2)
            if (dGmin == "" || dG < dGmin) {
                dGmin = dG                          # update the min dG value
                dGminid = $1                        # update the ID with the min dG
            }
        }
        END {
            print suffix, dGmin " (" dGminid ")"    # report the results
        }
    ' 10V1_cne_lig12/foo_str3a.csv
    

    输出:

    lig12, dG(rescored)
    lig12, 0.668396 (1)
    

    您会看到第一条记录与其 ID 一起被选中。 上面的 awk 脚本假设输入文件只有一个。 如果要一次处理多个 csv 文件,则需要 将"report the results" 行不仅放在END{} 块中,而且 可能FNR==1{} 块的开始 (只要完成一个文件处理)。

    [更新]
    您是否可以将 rescore_data3() 函数替换为:

    rescore_data3 () {
    str_name=$(basename "${str}" .csv)
    printf >&2 'Dataset for %s is being rescored...  ' "${str_name}"; sleep 0.1
    mkdir -p "${rescore}"/"${str_name}"
    # Apply the following AWK code for rescoring and final data collecting
    while read -r d; do
    awk -F', *' -v OFS=', ' '
        FNR==1 {
            if (suffix)                             # suppress the empty line
                print suffix, dGmin " (" dGminid ")"
                                                    # report the results
            dGmin = ""                              # initialize the min value
            path=FILENAME
            sub(/\/[^/]+$/,"",path)
            prefix=suffix=FILENAME
            sub(/_.*/, "", prefix)
            sub(/\/[^\/]+$/, "", suffix); sub(/^.*_/, "", suffix)
            if (FNR==NR)
                print prefix                        # print the header line
            next
        }
        {
            dG = sqrt((($3+12)/12)^2+(($2-240)/240)^2)
            if (dGmin == "" || dG < dGmin) {
                dGmin = dG                          # update the min dG value
                dGminid = $1                        # update the ID with the min dG
            }
        }
        END {
            print suffix, dGmin " (" dGminid ")"    # report the results
        }
    ' "${d}_"*/${str} > "${rescore}/"${str_name}"/"${d%%_*}".csv"
    done < <(find . -maxdepth 1 -type d -name '*_*_*' | awk -F '[_/]' '!seen[$2]++ {print $2}')
    }
    
    • 如前所述,您需要输入一个条件,例如if (suffix) ...FNR==1{} 块中以取消结果文件开头的空行。
    • 对不起,我打错了dgmin = "",应该是dGmin = "" 在我之前的回答中。
    • 最好将-p 选项放在mkdir 上,这样您就可以避免 mkdir: cannot create directory: File exists 错误。

    【讨论】:

    • 不匹配可能是因为我们为了方便而在本地编辑代码。您能否提供您的代码以及包含目录结构的 csv 文件,以便我重现您的问题?它不必包含整个文件。只需几个 csv 文件和嵌入 awk 的 bash 代码就会有很大帮助。 BR。
    • 感谢您准备文件。我当然已经下载了 zip 文件。你能允许我一两天的时间来反馈吗? BR。
    • 我已经通过修改您的 rescore_data3() 函数更新了我的答案。使用提供的文件进行测试。 BR。
    • 感谢您测试我的答案。很高兴知道它正在工作。你的回答是:1)是的,你可以。它将比print 更具可读性。 2) 绝对。优点是与将变量初始化为 0 相比,您不必关心可能值的范围。请记住在初始化时将变量重置为 ""(可能在 FNR==1{} 块中)。
    • 回答您的问题,您需要有单独的 IF 条件来分别找到最小值和最大值。干杯。
    猜你喜欢
    • 1970-01-01
    • 2021-05-13
    • 1970-01-01
    • 1970-01-01
    • 2013-06-18
    • 2017-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多