统计分析脚本#
脚本说明#
统计分析脚本用于对数据进行统计分析,包括描述性统计、相关性分析、频率分布等。
脚本代码#
#!/bin/bash
# 统计分析脚本
# 功能:对数据进行统计分析
# 作者:System Admin
# 日期:2024-01-01
set -euo pipefail
# 配置变量
INPUT_FILE=""
OUTPUT_FILE=""
DELIMITER=","
HAS_HEADER=true
COLUMN=""
ANALYSIS_TYPE="descriptive"
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# 日志函数
log() {
local level=$1
shift
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $@"
}
log_info() {
log "INFO" "$@"
}
log_error() {
log "ERROR" "$@"
}
# 检查输入文件
check_input_file() {
if [ ! -f "$INPUT_FILE" ]; then
log_error "输入文件不存在: $INPUT_FILE"
return 1
fi
if [ ! -r "$INPUT_FILE" ]; then
log_error "输入文件不可读: $INPUT_FILE"
return 1
fi
return 0
}
# 描述性统计
descriptive_stats() {
local file=$1
local column=$2
log_info "描述性统计: 列$column"
# 获取列号
local col_num=$(head -1 "$file" | awk -F"$DELIMITER" -v col="$column" '{for(i=1;i<=NF;i++) if($i==col) print i}')
if [ -z "$col_num" ]; then
log_error "列不存在: $column"
return 1
fi
# 提取数据
local data=()
if [ "$HAS_HEADER" = true ]; then
mapfile -t data < <(tail -n +2 "$file" | awk -F"$DELIMITER" -v col="$col_num" '$col ~ /^[0-9.]+$/ {print $col}')
else
mapfile -t data < <(awk -F"$DELIMITER" -v col="$col_num" '$col ~ /^[0-9.]+$/ {print $col}' "$file")
fi
if [ ${#data[@]} -eq 0 ]; then
log_error "没有有效的数值数据"
return 1
fi
# 计算统计量
local count=${#data[@]}
local sum=0
local min=${data[0]}
local max=${data[0]}
for value in "${data[@]}"; do
sum=$(echo "$sum + $value" | bc -l)
if (( $(echo "$value < $min" | bc -l) )); then
min=$value
fi
if (( $(echo "$value > $max" | bc -l) )); then
max=$value
fi
done
local mean=$(echo "scale=4; $sum / $count" | bc -l)
# 计算中位数
local sorted_data=($(printf '%s\n' "${data[@]}" | sort -n))
local median
if [ $((count % 2)) -eq 1 ]; then
median=${sorted_data[$((count / 2))]}
else
local mid1=${sorted_data[$((count / 2 - 1))]}
local mid2=${sorted_data[$((count / 2))]}
median=$(echo "scale=4; ($mid1 + $mid2) / 2" | bc -l)
fi
# 计算方差和标准差
local variance_sum=0
for value in "${data[@]}"; do
local diff=$(echo "$value - $mean" | bc -l)
local square=$(echo "$diff * $diff" | bc -l)
variance_sum=$(echo "$variance_sum + $square" | bc -l)
done
local variance=$(echo "scale=4; $variance_sum / $count" | bc -l)
local std_dev=$(echo "scale=4; sqrt($variance)" | bc -l)
# 计算四分位数
local q1_index=$((count / 4))
local q3_index=$((count * 3 / 4))
local q1=${sorted_data[$q1_index]}
local q3=${sorted_data[$q3_index]}
local iqr=$(echo "$q3 - $q1" | bc -l)
# 输出结果
echo "描述性统计"
echo "=========="
echo "列名: $column"
echo "样本数: $count"
echo ""
echo "集中趋势:"
echo " 均值: $mean"
echo " 中位数: $median"
echo " 众数: $(printf '%s\n' "${data[@]}" | sort | uniq -c | sort -nr | head -1 | awk '{print $2}')"
echo ""
echo "离散程度:"
echo " 最小值: $min"
echo " 最大值: $max"
echo " 极差: $(echo "$max - $min" | bc -l)"
echo " 第一四分位数 (Q1): $q1"
echo " 第三四分位数 (Q3): $q3"
echo " 四分位距 (IQR): $iqr"
echo " 方差: $variance"
echo " 标准差: $std_dev"
echo ""
echo "分布形态:"
echo " 偏度: $(python3 -c "import numpy as np; data = $([\"${data[@]}\", ] | sed 's/, /, /g'); print(f'{np.skew(data):.4f}')")"
echo " 峰度: $(python3 -c "import numpy as np; data = $([\"${data[@]}\", ] | sed 's/, /, /g'); print(f'{np.kurtosis(data):.4f}')")"
}
# 频率分布
frequency_distribution() {
local file=$1
local column=$2
local bins=${3:-10}
log_info "频率分布: 列$column, 分箱数=$bins"
# 获取列号
local col_num=$(head -1 "$file" | awk -F"$DELIMITER" -v col="$column" '{for(i=1;i<=NF;i++) if($i==col) print i}')
if [ -z "$col_num" ]; then
log_error "列不存在: $column"
return 1
fi
# 提取数据
local data=()
if [ "$HAS_HEADER" = true ]; then
mapfile -t data < <(tail -n +2 "$file" | awk -F"$DELIMITER" -v col="$col_num" '{print $col}')
else
mapfile -t data < <(awk -F"$DELIMITER" -v col="$col_num" '{print $col}' "$file")
fi
if [ ${#data[@]} -eq 0 ]; then
log_error "没有数据"
return 1
fi
# 检查是否为数值数据
local is_numeric=$(printf '%s\n' "${data[@]}" | grep -c "^[0-9.]*$")
if [ $is_numeric -eq ${#data[@]} ]; then
# 数值数据:创建直方图
echo "频率分布(直方图)"
echo "==================="
echo "列名: $column"
echo "分箱数: $bins"
echo ""
# 计算分箱边界
local sorted_data=($(printf '%s\n' "${data[@]}" | sort -n))
local min=${sorted_data[0]}
local max=${sorted_data[$((${#sorted_data[@]} - 1))]}
local bin_width=$(echo "scale=4; ($max - $min) / $bins" | bc -l)
# 统计每个分箱的频率
for ((i=0; i<bins; i++)); do
local bin_min=$(echo "$min + $i * $bin_width" | bc -l)
local bin_max=$(echo "$min + ($i + 1) * $bin_width" | bc -l)
local count=0
for value in "${data[@]}"; do
if (( $(echo "$value >= $bin_min" | bc -l) )) && (( $(echo "$value < $bin_max" | bc -l) )); then
count=$((count + 1))
fi
done
local frequency=$(echo "scale=2; $count * 100 / ${#data[@]}" | bc -l)
printf "[$(printf '%.2f' "$bin_min"), $(printf '%.2f' "$bin_max")): %d (%.2f%%)\n" "$count" "$frequency"
done
else
# 分类数据:统计频率
echo "频率分布(分类数据)"
echo "==================="
echo "列名: $column"
echo ""
printf '%-30s %10s %10s\n' "值" "频数" "频率"
printf '%-30s %10s %10s\n' "----------" "----------" "----------"
# 统计每个值的频率
declare -A freq_map
for value in "${data[@]}"; do
freq_map["$value"]=$((${freq_map["$value"]:-0} + 1))
done
# 按频率排序
for value in "${!freq_map[@]}"; do
echo "${freq_map[$value]} $value"
done | sort -rn | while read -r count value; do
local frequency=$(echo "scale=2; $count * 100 / ${#data[@]}" | bc -l)
printf '%-30s %10d %10.2f%%\n' "$value" "$count" "$frequency"
done
fi
}
# 相关性分析
correlation_analysis() {
local file=$1
local column1=$2
local column2=$3
log_info "相关性分析: 列$column1 vs 列$column2"
# 获取列号
local col1_num=$(head -1 "$file" | awk -F"$DELIMITER" -v col="$column1" '{for(i=1;i<=NF;i++) if($i==col) print i}')
local col2_num=$(head -1 "$file" | awk -F"$DELIMITER" -v col="$column2" '{for(i=1;i<=NF;i++) if($i==col) print i}')
if [ -z "$col1_num" ] || [ -z "$col2_num" ]; then
log_error "列不存在"
return 1
fi
# 提取数据
local data1=()
local data2=()
if [ "$HAS_HEADER" = true ]; then
while IFS="$DELIMITER" read -ra row; do
if [ "${#data1[@]}" -gt 0 ]; then # 跳过表头
data1+=("${row[$((col1_num - 1))]}")
data2+=("${row[$((col2_num - 1))]}")
fi
done < <(tail -n +2 "$file")
else
while IFS="$DELIMITER" read -ra row; do
data1+=("${row[$((col1_num - 1))]}")
data2+=("${row[$((col2_num - 1))]}")
done < "$file"
fi
# 计算相关性(使用Python)
python3 <<EOF
import numpy as np
data1 = [${data1[@]}]
data2 = [${data2[@]}]
# 计算皮尔逊相关系数
correlation = np.corrcoef(data1, data2)[0, 1]
print(f"相关性分析")
print(f"===========")
print(f"列1: $column1")
print(f"列2: $column2")
print(f"")
print(f"皮尔逊相关系数: {correlation:.4f}")
print(f"")
if correlation > 0.7:
print(f"结论: 强正相关")
elif correlation > 0.3:
print(f"结论: 中等正相关")
elif correlation > 0:
print(f"结论: 弱正相关")
elif correlation < -0.7:
print(f"结论: 强负相关")
elif correlation < -0.3:
print(f"结论: 中等负相关")
elif correlation < 0:
print(f"结论: 弱负相关")
else:
print(f"结论: 无相关")
EOF
}
# 生成分析报告
generate_report() {
local file=$1
log_info "生成分析报告"
{
echo "统计分析报告"
echo "============"
echo "文件: $file"
echo "时间: $(date)"
echo ""
echo "文件信息"
echo "=========="
echo "总行数: $(wc -l < "$file")"
echo "列数: $(head -1 "$file" | awk -F"$DELIMITER" '{print NF}')"
echo "文件大小: $(du -h "$file" | cut -f1)"
echo ""
echo "列名"
echo "===="
head -1 "$file" | awk -F"$DELIMITER" '{for(i=1;i<=NF;i++) print i": "$i}'
} > "$OUTPUT_FILE"
log_info "分析报告已生成: $OUTPUT_FILE"
}
# 显示帮助
show_help() {
echo "用法: $0 [选项] <分析类型> [参数]"
echo ""
echo "选项:"
echo " -i <文件> 输入文件"
echo " -o <文件> 输出文件"
echo " -d <分隔符> 分隔符(默认: ,)"
echo " -H 无表头"
echo " -h 显示帮助信息"
echo ""
echo "分析类型:"
echo " descriptive <列> 描述性统计"
echo " frequency <列> [分箱数] 频率分布"
echo " correlation <列1> <列2> 相关性分析"
echo ""
echo "示例:"
echo " $0 -i data.csv descriptive \"age\""
echo " $0 -i data.csv frequency \"age\" 10"
echo " $0 -i data.csv correlation \"age\" \"salary\""
}
# 主函数
main() {
# 解析选项
while getopts "i:o:d:Hh" opt; do
case $opt in
i)
INPUT_FILE="$OPTARG"
log_info "输入文件: $INPUT_FILE"
;;
o)
OUTPUT_FILE="$OPTARG"
log_info "输出文件: $OUTPUT_FILE"
;;
d)
DELIMITER="$OPTARG"
log_info "分隔符: $DELIMITER"
;;
H)
HAS_HEADER=false
log_info "无表头模式"
;;
h)
show_help
exit 0
;;
*)
log_error "无效选项: $opt"
show_help
exit 1
;;
esac
done
shift $((OPTIND - 1))
# 检查输入文件
if [ -z "$INPUT_FILE" ]; then
log_error "缺少输入文件"
show_help
exit 1
fi
if ! check_input_file; then
exit 1
fi
# 检查分析类型
if [ $# -eq 0 ]; then
log_error "缺少分析类型"
show_help
exit 1
fi
ANALYSIS_TYPE=$1
shift
# 执行分析
case $ANALYSIS_TYPE in
descriptive)
if [ $# -eq 0 ]; then
log_error "缺少列名"
exit 1
fi
descriptive_stats "$INPUT_FILE" "$1"
;;
frequency)
if [ $# -eq 0 ]; then
log_error "缺少列名"
exit 1
fi
frequency_distribution "$INPUT_FILE" "$1" "${2:-10}"
;;
correlation)
if [ $# -lt 2 ]; then
log_error "缺少列名"
exit 1
fi
correlation_analysis "$INPUT_FILE" "$1" "$2"
;;
*)
log_error "无效的分析类型: $ANALYSIS_TYPE"
show_help
exit 1
;;
esac
# 生成报告
if [ -n "$OUTPUT_FILE" ]; then
generate_report "$INPUT_FILE"
fi
}
# 执行主函数
main "$@"使用说明#
添加执行权限:
chmod +x stats_analysis.sh基本用法:
# 描述性统计 ./stats_analysis.sh -i data.csv descriptive "age" # 频率分布 ./stats_analysis.sh -i data.csv frequency "age" 10 # 相关性分析 ./stats_analysis.sh -i data.csv correlation "age" "salary"高级用法:
# 输出到文件 ./stats_analysis.sh -i data.csv -o report.txt descriptive "age" # 指定分隔符 ./stats_analysis.sh -i data.txt -d ";" descriptive "age" # 无表头模式 ./stats_analysis.sh -i data.csv -H descriptive "age"
功能特点#
- 描述性统计(均值、中位数、众数、方差、标准差等)
- 频率分布(直方图、分类统计)
- 相关性分析(皮尔逊相关系数)
- 多种数据格式支持
- 详细的统计报告
依赖项#
- bc: 用于数值计算
- python3: 用于高级统计计算
- numpy: 用于统计分析(可选)
注意事项#
- 确保数据格式正确
- 相关性分析需要数值数据
- 大数据集分析可能需要较长时间
- 某些统计功能需要numpy
- 分箱数影响频率分布的粒度