所以我制作了这个脚本,它接受 CSV 文件作为参数,然后删除其中唯一值少于 2 个的任何字段。这是因为无论如何,我正在处理的数据在每个字段中都有 2 个值。 Reddit 数据看起来就是这样。
基本上我所做的是使用 cut 循环遍历每一列,然后对每一列进行唯一排序,然后如果小于 2,我会保存该列号。然后,我循环遍历我记下的所有列号,并创建一个大剪切命令来删除它们。
问题是它在处理大文件时运行速度非常慢。
如果可能的话,我希望能够加快速度,但我不熟悉使用更高级的命令。如果有人能向我展示一种更快的方法来实现这一目标,我会很高兴!谢谢。
代码:
#!/bin/bash
#find number of fields
num_items=$(cat $1 | head -n 1 | grep -o , | wc -w)
num_items=$((num_items + 0))
echo "Searching all $num_items columns for redundancy"
cols=()
command="-f"
for ((i = 1; i < $num_items; i++))
do
num_vals=$(cat $1 | cut -d, -f$i | sort -u | wc -w)
x=$(($num_vals+0))
#remove column if it has less than 2 values in its column
#lt 3 as we want to discard the field name at the top
if [ $x -lt 3 ]
then
cols+=("$i")
fi
bit="$i-$i,"
command="${command}${bit}"
done
command="${command}$num_items-$num_items"
echo ""
for col in "${cols[@]}"; do
sed_reg="s/$col-$col,//"
command=$(echo "$command" | sed $sed_reg)
echo "col $col has been removed"
done
command="cut -d, ${command} $1"
$command > pruned_cols.csv
较小的样本数据:https://ufile.io/27bm31d6
〜70k 行。样本数据:https://ufile.io/qvglxajr
系统:使用 zsh 的 macOS
答案1
看看这会让你走多远:
$ cut --complement -d, -f$(awk -F, '
NR > 1 {for (i=1; i<=NF; i++) CNT[i, $i]++
}
END {for (c in CNT) if (CNT[c] == (NR-1)) {split (c, T, SUBSEP)
printf "%s%d", DL, T[1]
DL = ","
}
}
' /tmp/small_data.csv) /tmp/small_data.csv
鉴于您的cut
版本有该--complement
选项。否则反转打印输出逻辑。如果您在该部分中awk
失败,请将其保留在每行处理中。NR
END
它遍历所有行中的所有字段(标题除外)并计算唯一内容。在该END
部分中,如果CNT
等于行数减去标题(即该字段在所有行中具有相同的内容),则拆分索引并打印字段号。