大数据分析工具

《区域水环境污染数据分析实践》
Data analysis practice of regional water environment pollution

苏命、王为东
中国科学院大学资源与环境学院
中国科学院生态环境研究中心

2025-04-09

正则表达式

匹配数字

匹配数字:

  • 匹配任意数字字符。
  • :匹配一个或多个数字字符。

匹配字母:

  • :匹配任意字母、数字或下划线字符。
  • +:匹配一个或多个字母、数字或下划线字符。

匹配数字

匹配空白字符:

  • :匹配任意空白字符,包括空格、制表符、换行符等。
  • +:匹配一个或多个空白字符。

匹配特定字符:

  • [abc]:匹配字符 a、b 或 c 中的任意一个。
  • [a-z]:匹配任意小写字母。
  • [A-Z]:匹配任意大写字母。
  • 0-9:匹配任意数字。

匹配数字

匹配重复次数:

  • {n}:匹配前一个字符恰好 n 次。
  • {n,}:匹配前一个字符至少 n 次。
  • {n,m}:匹配前一个字符至少 n 次,但不超过 m 次。

匹配边界:

  • ^:匹配字符串的开头。
  • $:匹配字符串的结尾。

匹配数字

匹配特殊字符:

  • :转义特殊字符,使其按字面意义匹配。
  • .:匹配任意单个字符。
  • |:表示“或”关系,匹配两个或多个表达式之一。

匹配次数:

  • *:匹配前一个字符零次或多次。
  • +:匹配前一个字符一次或多次。
  • ?:匹配前一个字符零次或一次。

匹配数字

分组和捕获:

  • ():将一系列模式组合成一个单元,可与特殊字符一起使用。

预定义字符集:

  • 任意数字,相当于 0-9
  • :任意字母、数字或下划线字符,相当于 [a-zA-Z0-9_]。
  • :任意空白字符,相当于 [ 。

实例

library(babynames)
(x <- c("apple", "apppple", "abc123def"))
[1] "apple"     "apppple"   "abc123def"
x[str_detect(x, "[0-9]")]
[1] "abc123def"
x[str_detect(x, "abc[0-9]+")]
[1] "abc123def"
x[str_detect(x, "pp")]
[1] "apple"   "apppple"
x[str_detect(x, "p{4}")]
[1] "apppple"
x[str_detect(x, "p{4}")]
[1] "apppple"
x[str_detect("apple", "ap*")]
[1] "apple"     "apppple"   "abc123def"
x[str_detect("apple", "app*")]
[1] "apple"     "apppple"   "abc123def"
x[str_detect("apple", "a..le")]
[1] "apple"     "apppple"   "abc123def"

练习

找出babyname中名字含有ar的行

# A tibble: 199,504 × 5
    year sex   name         n    prop
   <dbl> <chr> <chr>    <int>   <dbl>
 1  1880 F     Mary      7065 0.0724 
 2  1880 F     Margaret  1578 0.0162 
 3  1880 F     Sarah     1288 0.0132 
 4  1880 F     Clara     1226 0.0126 
 5  1880 F     Martha    1040 0.0107 
 6  1880 F     Carrie     949 0.00972
 7  1880 F     Pearl      569 0.00583
 8  1880 F     Marie      471 0.00483
 9  1880 F     Harriet    319 0.00327
10  1880 F     Caroline   306 0.00314
# ℹ 199,494 more rows

练习

找出babyname中名字含有ar或者以ry结尾的行。

# A tibble: 199,504 × 5
    year sex   name         n    prop
   <dbl> <chr> <chr>    <int>   <dbl>
 1  1880 F     Mary      7065 0.0724 
 2  1880 F     Margaret  1578 0.0162 
 3  1880 F     Sarah     1288 0.0132 
 4  1880 F     Clara     1226 0.0126 
 5  1880 F     Martha    1040 0.0107 
 6  1880 F     Carrie     949 0.00972
 7  1880 F     Pearl      569 0.00583
 8  1880 F     Marie      471 0.00483
 9  1880 F     Harriet    319 0.00327
10  1880 F     Caroline   306 0.00314
# ℹ 199,494 more rows

Linux基础知识与开发工具

SSH - 安全远程连接

# 连接到远程服务器
ssh username@remote.server.com

# 使用特定端口连接
ssh -p 2222 username@remote.server.com

# 执行远程命令
ssh username@server "ls -l /tmp"

案例
- 远程管理云服务器
- 自动化脚本执行

Windows下的SSH工具 - PuTTY

PuTTY界面

# 主要功能:
1. 保存会话配置(IP/端口/认证信息)
2. 支持SSH/Telnet/Serial连接
3. 公钥认证(配合Pageant使用)
4. 端口转发(SSH隧道)

案例
- 连接Linux服务器进行管理
- 建立SSH隧道访问内网资源

SCP - 安全文件传输

# 复制本地文件到远程
scp file.txt username@remote:/path/to/dest

# 从远程复制到本地
scp username@remote:/path/file.txt .

# 递归复制目录
scp -r dir/ username@remote:/path/

案例
- 部署网站文件到生产环境
- 备份远程日志文件

Windows下的SCP工具 - WinSCP

WinSCP界面 w:400

# 主要特性:
- 图形化SFTP/SCP客户端
- 与PuTTY集成
- 支持拖拽操作
- 可保存常用连接
- 批处理脚本功能

案例
- 可视化管理服务器文件
- 本地与服务器间同步代码

Windows替代bash的工具

1. Git Bash

# 包含常用Linux命令
ls, grep, ssh, scp, awk等

2. WSL (Windows Subsystem for Linux)

# 完整Linux环境
sudo apt install python3

3. Cygwin

# POSIX兼容环境
cygwin.com/setup-x86_64.exe

Windows终端工具推荐

工具 特点 适用场景
Windows Terminal 多标签/色彩支持 日常开发
MobaXterm 内置X11/插件 远程开发
Tabby 跨平台/主题丰富 多平台用户
ConEmu 高度可定制 高级用户

开发工具跨平台方案

最佳实践
1. 代码编辑器统一使用VS Code(全平台支持)
- 配合Remote-SSH插件
2. 数据库工具使用DBeaver/DataGrip
3. 版本控制使用Git GUI(GitKraken/Fork)

# 保持环境一致的建议:
- 使用WSL2开发环境
- 配置相同的.ssh/config文件
- 共享相同的IDE配置

grep - 文本搜索

# 基本搜索
grep "error" logfile.txt

# 递归搜索目录
grep -r "function" src/

# 显示行号
grep -n "TODO" *.py

# 反向匹配
grep -v "success" results.log

案例
- 在日志中查找错误信息
- 分析代码库中的特定模式

sed - 流编辑器

# 替换文本
sed 's/old/new/g' file.txt

# 删除空行
sed '/^$/d' file.txt

# 原地编辑文件
sed -i 's/python/python3/g' script.sh

案例
- 批量重命名文件中的字符串
- 清理数据文件中的不规范格式

awk - 文本处理

# 打印特定列
awk '{print $1,$3}' data.csv

# 条件过滤
awk '$3 > 100 {print $0}' sales.txt

# 使用分隔符
awk -F',' '{print $2}' users.csv

案例
- 分析服务器日志统计状态码
- 处理CSV格式数据

find & xargs - 文件查找处理

# 查找并删除
find . -name "*.tmp" -delete

# 查找并处理
find /var/log -name "*.log" | xargs ls -lh

# 复杂组合
find src/ -type f -name "*.js" | xargs grep -l "deprecated"

案例
- 清理旧临时文件
- 批量处理项目文件

代码编辑器

  • VS Code:现代轻量级编辑器

    • 丰富的插件生态
    • 内置Git支持
  • Vim:终端高效编辑器

    vim file.txt
  • RStudio:R语言集成环境

  • JupyterLab:交互式笔记本环境

Git版本控制

# 基本工作流
git clone https://repo.url
git add .
git commit -m "message"
git push

# 分支管理
git checkout -b new-feature
git merge main

案例
- 团队协作开发
- 版本回滚与问题追踪

MySQL数据库

-- 基本查询
SELECT * FROM users WHERE age > 18;

-- 创建表
CREATE TABLE products (
  id INT PRIMARY KEY,
  name VARCHAR(100)
);

-- 数据操作
INSERT INTO products VALUES (1, 'Laptop');
UPDATE products SET price=999 WHERE id=1;

案例
- Web应用数据存储
- 数据分析与报表生成

公开数据获取

案例:全国气象数据

#!/bin/bash
logfn="${HOME}/service/log/nationalairquality/nationalairquality.log"
workdirfn="${HOME}/service/nationalairquality/"
mkdir -p "$(dirname "${logfn}")"
touch "${logfn}"

echo "$(date '+%Y-%m-%d %H:%M:%S'): 下载大气质量数据" >>"${logfn}"

declare -a citynames

citynames=(北京市 石家庄市 秦皇岛市)

jsonfn="${workdirfn}/nationalairquality_$(date '+%Y%d%m%H').json"
jsonfn="nationalairquality_$(date '+%Y%d%m%H').json"
# [[ -f "${jsonfn}" ]] && rm "${jsonfn}"
echo "[" >"${jsonfn}"

for cityname in "${citynames[@]}"; do
  echo "下载${cityname}空气质量数据..." >>"${logfn}"
  curl "https://air.cnemc.cn:18007/CityData/GetAQIDataPublishLive?cityName=${cityname}" \
    -H 'Accept: */*' \
    -H 'Accept-Language: en-US,en;q=0.9' \
    -H 'Connection: keep-alive' \
    -H 'Referer: https://air.cnemc.cn:18007/' \
    -H 'Sec-Fetch-Dest: empty' \
    -H 'Sec-Fetch-Mode: cors' \
    -H 'Sec-Fetch-Site: same-origin' \
    -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36' \
    -H 'X-Requested-With: XMLHttpRequest' \
    -H 'sec-ch-ua: "Google Chrome";v="119", "Chromium";v="119", "Not?A_Brand";v="24"' \
    -H 'sec-ch-ua-mobile: ?0' \
    -H 'sec-ch-ua-platform: "macOS"' \
    --compressed --silent | jq | sed -e '1d' -e '$d' -e 's/^\( *}\)$/\1,/' >>"${jsonfn}"
done
sed -i '' '$s/},/}/' "${jsonfn}"
echo "]" >>"${jsonfn}"

echo "大气质量数据下载完成!" >>"${logfn}"
echo "开始上传数据库..." >>"${logfn}"
/home/ming/bin/getnationalairquality.R "${jsonfn}"
echo "上传数据库完毕!" >>"${logfn}"

R代码

#!/usr/bin/Rscript

jsonfn <- commandArgs(TRUE)[1]
# jsonfn <- "~/nationalairquality_2023191219.json"
jsondf <- jsonlite::fromJSON(jsonfn, flatten = TRUE)
# metadf <- tibble::as_tibble(jsondf) |>
#   dplyr::select(site = StationCode, name = PositionName, Area, lon = Longitude, lat = Latitude) |>
#   dplyr::mutate(lon = as.numeric(lon), lat = as.numeric(lat))
# DBI::dbWriteTable(conn, "metadf", metadf, overwrite = TRUE, row.names = FALSE)
airqualitydf <- tibble::as_tibble(jsondf) |>
  dplyr::select(
    datetime = TimePoint,
    site = StationCode,
    `CO_mg/m3` = CO,
    `CO_24h_mg/m3` = CO_24h,
    `NO2_μg/m3` = NO2,
    `NO2_24h_μg/m3` = NO2_24h,
    `O3_μg/m3` = O3,
    `O3_24h_μg/m3` = O3_24h,
    `O3_8h_μg/m3` = O3_8h,
    `O3_8h_24h_μg/m3` = O3_8h_24h,
    `PM10_μg/m3` = PM10,
    `PM10_24h_μg/m3` = PM10_24h,
    `PM2.5_μg/m3` = PM2_5,
    `PM2.5_24h_μg/m3` = PM2_5_24h,
    `SO2_μg/m3` = SO2,
    `SO2_24h_μg/m3` = SO2_24h,
    `NO_μg/m3` = NO,
    `NO_24h_μg/m3` = NO_24h,
    `NOx_μg/m3` = NOx,
    `NOx_24h_μg/m3` = NOx_24h,
    AQI,
    COLevel,
    NO2Level,
    O3Level,
    O3_8hLevel,
    PM10Level,
    PM2_5Level,
    SO2Level,
    PrimaryPollutant,
    Quality,
    Unheathful
  ) |>
  dplyr::mutate(dplyr::across(
    `CO_mg/m3`:AQI,
    ~ round(readr::parse_number(.x), 4)
  )) |>
  dplyr::mutate(datetime = lubridate::as_datetime(datetime))
conn <- cctdb::get_dbconn("nationalairquality", writepermission = TRUE)
DBI::dbWriteTable(
  conn,
  "airqualitydf",
  airqualitydf,
  append = TRUE,
  row.names = FALSE
)
DBI::dbDisconnect(conn)

欢迎讨论!

苏命|https://drwater.net; https://drwater.net/team/ming-su/; Slides