Coverage for agentos/marketplace/skills/data-analysis/data-analysis.py: 2%
85 statements
« prev ^ index » next coverage.py v7.14.3, created at 2026-07-06 08:01 +0800
« prev ^ index » next coverage.py v7.14.3, created at 2026-07-06 08:01 +0800
1"""
2data-analysis — 基本数据分析:描述性统计、相关性、频率分布。
4Category: data
5"""
8def run(action: str, file_path: str = "", column: str = "", group_by: str = "",
9 delimiter: str = ",", encoding: str = "utf-8") -> str:
10 """数据分析工具。action: describe/correlation/freq/top_n。输入为 CSV 文件。"""
11 import csv, os, math, collections
13 if not file_path or not os.path.isfile(file_path):
14 return f"[data-analysis] 文件不存在: {file_path}"
16 try:
17 with open(file_path,"r",encoding=encoding,newline="") as f:
18 reader = csv.DictReader(f, delimiter=delimiter)
19 if reader.fieldnames is None:
20 return "[data-analysis] 无法解析表头"
21 headers = list(reader.fieldnames)
22 rows = list(reader)
24 def _numeric(col):
25 vals = []
26 for row in rows:
27 v = row.get(col,"")
28 try: vals.append(float(v))
29 except ValueError: pass
30 return vals
32 if action == "describe":
33 target = [column] if column and column in headers else headers
34 result = [f"文件: {file_path}", f"行数: {len(rows)}", ""]
35 for col in target:
36 vals = _numeric(col)
37 if not vals:
38 result.append(f"{col}: 无数值数据")
39 continue
40 n = len(vals)
41 mean = sum(vals)/n
42 srt = sorted(vals)
43 median = srt[n//2] if n%2 else (srt[n//2-1]+srt[n//2])/2
44 var = sum((x-mean)**2 for x in vals)/n
45 std = math.sqrt(var)
46 result.append(
47 f"{col}: count={n}, mean={mean:.4f}, std={std:.4f}, "
48 f"min={min(vals):.4f}, 25%={srt[n//4]:.4f}, median={median:.4f}, "
49 f"75%={srt[3*n//4]:.4f}, max={max(vals):.4f}"
50 )
51 return "\n".join(result)
53 if action == "correlation":
54 numeric_cols = [h for h in headers if _numeric(h)]
55 if len(numeric_cols) < 2:
56 return "[data-analysis] 需要至少 2 个数值列"
57 if column:
58 targets = [column] if column in numeric_cols else numeric_cols[:2]
59 else:
60 targets = numeric_cols[:min(5, len(numeric_cols))]
62 def _pearson(xs, ys):
63 n = min(len(xs), len(ys))
64 mx, my = sum(xs)/n, sum(ys)/n
65 num = sum((xs[i]-mx)*(ys[i]-my) for i in range(n))
66 dx = math.sqrt(sum((x-mx)**2 for x in xs))
67 dy = math.sqrt(sum((y-my)**2 for y in ys))
68 return num/(dx*dy) if dx and dy else 0
70 result = ["相关性矩阵:", ""]
71 result.append(" " + " ".join(f"{t:>8}" for t in targets))
72 for t1 in targets:
73 row_vals = [f"{t1:<8}"]
74 vals1 = _numeric(t1)
75 for t2 in targets:
76 if t1 == t2: row_vals.append(f"{1.0:>8.3f}")
77 elif t1 < t2: row_vals.append(f"{_pearson(vals1,_numeric(t2)):>8.3f}")
78 else: row_vals.append(" ")
79 result.append(" ".join(row_vals))
80 return "\n".join(result)
82 if action == "freq":
83 if not column or column not in headers:
84 return f"[data-analysis] 请指定有效列名。可用: {', '.join(headers)}"
85 counter = collections.Counter(row.get(column,"") for row in rows)
86 lines = [f"{column} 频率分布 (共{len(counter)}个不同值):"]
87 for val, cnt in counter.most_common(20):
88 pct = cnt/len(rows)*100
89 lines.append(f" {val}: {cnt} ({pct:.1f}%)")
90 return "\n".join(lines)
92 if action == "top_n":
93 if not column or column not in headers:
94 return f"[data-analysis] 请指定有效列名。可用: {', '.join(headers)}"
95 vals = []
96 for row in rows:
97 v = row.get(column,"")
98 try: vals.append((float(v), row))
99 except ValueError: pass
100 vals.sort(key=lambda x: x[0], reverse=True)
101 lines = [f"{column} Top 10:"]
102 for i,(val,row) in enumerate(vals[:10]):
103 lines.append(f" {i+1}. {column}={val} | {dict(row)}")
104 return "\n".join(lines)
106 return f"[data-analysis] 未知操作: {action}, 支持: describe/correlation/freq/top_n"
107 except Exception as e:
108 return f"[data-analysis] 失败: {e}"
111__all__ = ["run"]