R语言入门学习教程,从入门到精通,R语言数据计算与分组统计(9)

R语言数据计算与分组统计


一、数据计算

1. 求和 sum()

r 复制代码
# 创建一个数值向量
scores <- c(85, 90, 78, 92, 88)

# 计算所有元素的总和
total <- sum(scores)  # sum()函数将向量中所有数值相加
print(total)  # 输出: 433

2. 求均值 mean()

r 复制代码
# 计算平均值
average <- mean(scores)  # mean()计算算术平均数
print(average)  # 输出: 86.6

3. 求最大值 max()

r 复制代码
# 找出最大值
max_score <- max(scores)  # max()返回向量中的最大值
print(max_score)  # 输出: 92

4. 求最小值 min()

r 复制代码
# 找出最小值
min_score <- min(scores)  # min()返回向量中的最小值
print(min_score)  # 输出: 78

5. 求中位数 median()

r 复制代码
# 计算中位数(排序后中间位置的值)
median_score <- median(scores)  # median()计算中位数
print(median_score)  # 输出: 88

6. 求众数(自定义函数)

r 复制代码
# R基础包没有内置众数函数,需要自定义
get_mode <- function(x) {
  # 计算每个唯一值出现的频率
  freq_table <- table(x)  # table()创建频数表
  # 找出最大频数对应的值(可能有多个)
  mode_value <- names(freq_table)[freq_table == max(freq_table)]
  return(mode_value)
}

# 测试数据(包含重复值)
test_scores <- c(85, 90, 85, 92, 85, 88)
mode_result <- get_mode(test_scores)
print(mode_result)  # 输出: "85"

7. 求方差 var()

r 复制代码
# 计算样本方差(除以n-1)
variance <- var(scores)  # var()计算样本方差
print(variance)  # 输出: 31.3

# 计算总体方差(除以n)
pop_variance <- var(scores) * (length(scores)-1)/length(scores)
print(pop_variance)  # 输出: 25.04

8. 求标准差 sd()

r 复制代码
# 计算样本标准差(方差的平方根)
std_dev <- sd(scores)  # sd()计算样本标准差
print(std_dev)  # 输出: 5.59464

9. 求分位数 quantile()

r 复制代码
# 计算不同分位数的值
# 默认计算0%、25%、50%、75%、100%分位数
quantiles <- quantile(scores)  
print(quantiles)
# 输出:
#   0%   25%   50%   75%  100% 
# 78.0  86.5  88.0  90.5  92.0 

# 计算自定义分位数(如10%、30%、60%、90%)
custom_quantiles <- quantile(scores, probs = c(0.1, 0.3, 0.6, 0.9))
print(custom_quantiles)

10. 求多个计算结果 summary()

r 复制代码
# summary()一次性计算:最小值、1/4分位数、中位数、均值、3/4分位数、最大值
summary_stats <- summary(scores)  
print(summary_stats)
# 输出:
#    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#   78.0    86.5    88.0    86.6    90.5    92.0 

二、数据分组统计

准备工作:创建示例数据框

r 复制代码
# 创建一个学生成绩数据框,用于演示分组统计
students <- data.frame(
  class = c("A", "A", "B", "B", "C", "C", "A", "B", "C"),  # 班级
  gender = c("M", "F", "M", "F", "M", "F", "M", "F", "M"),  # 性别
  score = c(85, 90, 78, 88, 92, 86, 89, 84, 91),            # 成绩
  age = c(18, 17, 18, 19, 18, 17, 19, 18, 18)               # 年龄
)
print(students)

1. apply() 函数(用于矩阵/数据框的行或列)

r 复制代码
# 创建一个矩阵用于演示
score_matrix <- matrix(c(85, 90, 78, 92, 88, 84), nrow = 3, ncol = 2)
colnames(score_matrix) <- c("Math", "English")
rownames(score_matrix) <- c("Student1", "Student2", "Student3")
print(score_matrix)

# apply(X, MARGIN, FUN, ...)
# X: 要处理的矩阵或数据框
# MARGIN: 1表示行,2表示列
# FUN: 要应用的函数

# 按行计算每行的平均值(MARGIN=1)
row_mean <- apply(score_matrix, 1, mean)  # 1表示对每一行应用mean函数
print(row_mean)

# 按列计算每列的总和(MARGIN=2)
col_sum <- apply(score_matrix, 2, sum)  # 2表示对每一列应用sum函数
print(col_sum)

# 按列计算标准差
col_sd <- apply(score_matrix, 2, sd)
print(col_sd)

2. lapply() 函数(对列表应用函数,返回列表)

r 复制代码
# 创建一个包含多个向量的列表
score_list <- list(
  class_A = c(85, 90, 89),
  class_B = c(78, 88, 84),
  class_C = c(92, 86, 91)
)

# lapply()对列表的每个元素应用函数,返回列表
# 计算每个班级的平均分
mean_list <- lapply(score_list, mean)  # 对列表每个元素计算均值
print(mean_list)

# 计算每个班级的最高分
max_list <- lapply(score_list, max)
print(max_list)

3. sapply() 函数(简化结果,尽量返回向量或矩阵)

r 复制代码
# sapply()是lapply()的简化版本,结果更简洁
# 计算每个班级的平均分(返回向量)
mean_vector <- sapply(score_list, mean)  # 返回命名的数值向量
print(mean_vector)
print(class(mean_vector))  # 查看结果类型:"numeric"

# 计算多个统计量(返回矩阵)
multiple_stats <- sapply(score_list, function(x) {
  c(mean = mean(x), sd = sd(x), max = max(x))
})
print(multiple_stats)

4. tapply() 函数(按因子分组计算)

r 复制代码
# tapply(X, INDEX, FUN, ...)
# X: 要计算的数值向量
# INDEX: 因子或因子列表(分组依据)
# FUN: 要应用的函数

# 按班级(class)分组计算平均分
class_mean <- tapply(students$score, students$class, mean)
print(class_mean)
# 输出:
#        A    B    C 
# 88.0000 83.3333 89.6667 

# 按性别分组计算最高分
gender_max <- tapply(students$score, students$gender, max)
print(gender_max)
# 输出:
#  F  M 
# 90 92 

# 按班级和性别两个因素分组(返回矩阵)
class_gender_mean <- tapply(students$score, 
                           list(students$class, students$gender), 
                           mean)
print(class_gender_mean)
# 输出:
#         F   M
#   A 90.0  87
#   B 88.0  81
#   C 86.0  NA   (C班没有男生?检查:C班只有91分的是男生)

5. 分组统计函数 aggregate()

r 复制代码
# aggregate()是更易于使用的分组统计函数

# 基本用法:按单个变量分组
# aggregate(待计算列 ~ 分组列, 数据, 函数)
class_agg <- aggregate(score ~ class, data = students, FUN = mean)
print(class_agg)
# 输出:
#   class    score
# 1     A 88.00000
# 2     B 83.33333
# 3     C 89.66667

# 按多个变量分组
# 使用cbind()指定多列,或使用点号.
multi_agg <- aggregate(cbind(score, age) ~ class + gender, 
                       data = students, 
                       FUN = mean)
print(multi_agg)

# 使用.表示所有其他列分组(不推荐有太多列时使用)
# aggregate(. ~ class, data = students, FUN = mean)

# 使用多个函数的结果(需要自定义)
agg_with_multiple <- aggregate(score ~ class, 
                               data = students, 
                               FUN = function(x) c(mean = mean(x), sd = sd(x)))
print(agg_with_multiple)

6. 分组函数 group_by()(来自dplyr包)

r 复制代码
# 首先安装并加载dplyr包
# install.packages("dplyr")  # 如果未安装,取消注释运行
library(dplyr)   # 加载dplyr包

# group_by()配合summarise()实现分组统计
# 使用管道操作符 %>% 使代码更易读

# 按班级分组,计算平均分和标准差
grouped_result <- students %>%
  group_by(class) %>%           # 按class列分组
  summarise(                    # 对每组计算汇总统计
    count = n(),                # n()计算每组行数
    mean_score = mean(score),   # 平均分
    sd_score = sd(score),       # 标准差
    max_score = max(score),     # 最高分
    min_score = min(score)      # 最低分
  )
print(grouped_result)

# 按班级和性别分组
grouped_multi <- students %>%
  group_by(class, gender) %>%   # 按两个变量分组
  summarise(
    avg_score = mean(score),
    avg_age = mean(age),
    total_students = n()
  )
print(grouped_multi)

# 使用mutate()添加分组后的计算列
students_with_group_mean <- students %>%
  group_by(class) %>%
  mutate(
    class_mean = mean(score),    # 添加该生所在班级的平均分
    deviation = score - class_mean  # 与班级平均分的差值
  )
print(students_with_group_mean)

三、数据透视表

准备工作:安装并加载reshape2包

r 复制代码
# 安装并加载reshape2包(包含dcast函数)
# install.packages("reshape2")  # 如果未安装,取消注释运行
library(reshape2)

# 创建一个销售数据示例
sales <- data.frame(
  product = c("A", "A", "B", "B", "C", "C", "A", "B", "C"),
  region = c("North", "South", "North", "South", "North", "South", "East", "East", "East"),
  quarter = c("Q1", "Q1", "Q1", "Q2", "Q2", "Q2", "Q3", "Q3", "Q3"),
  amount = c(100, 150, 200, 120, 180, 130, 170, 210, 160)
)
print(sales)

1. dcast() 函数(从长格式转换为宽格式/数据透视表)

r 复制代码
# dcast(data, formula, fun.aggregate, value.var)
# data: 要转换的数据框
# formula: 行变量 ~ 列变量
# fun.aggregate: 聚合函数(可选)
# value.var: 要填充到单元格的值列

# 基本数据透视:产品作为行,地区作为列,金额作为值
pivot1 <- dcast(sales, product ~ region, value.var = "amount")
print(pivot1)
# 输出:
#   product East North South
# 1       A  170   100   150
# 2       B  210   200   120
# 3       C  160   180   130

# 如果有重复值,需要指定聚合函数
# 创建有重复数据的新示例
orders <- data.frame(
  product = c("A", "A", "B", "A"),
  city = c("BJ", "SH", "BJ", "BJ"),
  sales = c(100, 200, 150, 50)
)

# 使用dcast时遇到重复组合会报错,需要用聚合函数
pivot_with_agg <- dcast(orders, product ~ city, 
                        value.var = "sales", 
                        fun.aggregate = sum)  # 对重复值求和
print(pivot_with_agg)
# 输出:
#   product BJ SH
# 1       A 150 200
# 2       B 150  NA

# 更复杂的透视表:行=产品,列=季度,值=金额和
pivot_complex <- dcast(sales, product ~ quarter, 
                       value.var = "amount", 
                       fun.aggregate = sum)
print(pivot_complex)

# 多变量作为行和列
pivot_multi <- dcast(sales, product + region ~ quarter, 
                     value.var = "amount", 
                     fun.aggregate = sum)
print(pivot_multi)

2. gather() 函数(来自tidyr包,宽格式转长格式)

r 复制代码
# 安装并加载tidyr包
# install.packages("tidyr")  # 如果未安装,取消注释运行
library(tidyr)

# 创建宽格式数据(类似透视后的结果)
wide_data <- data.frame(
  product = c("A", "B", "C"),
  Q1 = c(250, 200, 180),
  Q2 = c(150, 120, 130),
  Q3 = c(170, 210, 160)
)
print(wide_data)
# 输出:
#   product  Q1  Q2  Q3
# 1       A 250 150 170
# 2       B 200 120 210
# 3       C 180 130 160

# gather(data, key, value, ...)
# data: 要转换的数据框
# key: 新列名(存放原列名)
# value: 新列名(存放原值)
# ...: 要收集的列

# 将宽格式转换为长格式
long_data <- gather(wide_data, 
                    key = "quarter",    # 季度信息将存放在这一列
                    value = "amount",   # 销售额将存放在这一列
                    Q1, Q2, Q3)         # 指定要收集的列
print(long_data)
# 输出:
#   product quarter amount
# 1       A      Q1    250
# 2       B      Q1    200
# 3       C      Q1    180
# 4       A      Q2    150
# 5       B      Q2    120
# 6       C      Q2    130
# 7       A      Q3    170
# 8       B      Q3    210
# 9       C      Q3    160

# 使用负号排除不需要收集的列
long_data2 <- gather(wide_data, 
                     key = "quarter", 
                     value = "amount", 
                     -product)  # 除product外所有列都收集
print(long_data2)  # 结果与上面相同

3. spread() 函数(长格式转宽格式,gather的逆操作)

r 复制代码
# spread(data, key, value)
# data: 要转换的数据框
# key: 包含新列名的列
# value: 包含值的列

# 将上面转换的长格式数据恢复为宽格式
wide_recovered <- spread(long_data, 
                         key = "quarter",    # 用quarter列的值作为新列名
                         value = "amount")   # 用amount列的值填充
print(wide_recovered)
# 输出应与原来的wide_data相同
#   product  Q1  Q2  Q3
# 1       A 250 150 170
# 2       B 200 120 210
# 3       C 180 130 160

# 复杂示例:处理需要聚合的情况
sales_long <- data.frame(
  product = c("A", "A", "B", "B"),
  quarter = c("Q1", "Q2", "Q1", "Q2"),
  region = c("North", "South", "North", "South"),
  amount = c(100, 150, 200, 120)
)

# spread在有重复组合时可能失败
# 先使用dcast或者先聚合再spread
library(dplyr)
sales_aggregated <- sales_long %>%
  group_by(product, quarter) %>%
  summarise(total_amount = sum(amount))

wide_sales <- spread(sales_aggregated, 
                     key = "quarter", 
                     value = "total_amount")
print(wide_sales)
# 输出:
#   product  Q1  Q2
# 1       A 100 150
# 2       B 200 120

四、综合案例:完整的数据分组统计与透视分析

r 复制代码
# 加载必要的包
library(dplyr)
library(reshape2)

# 创建更完整的销售数据集
set.seed(123)  # 设置随机种子,确保结果可重现
sales_data <- data.frame(
  date = rep(c("2024-01", "2024-02", "2024-03"), each = 20),
  product = sample(c("Laptop", "Phone", "Tablet"), 60, replace = TRUE),
  region = sample(c("North", "South", "East", "West"), 60, replace = TRUE),
  sales_amount = round(runif(60, 100, 1000), 0),
  quantity = sample(1:20, 60, replace = TRUE)
)
head(sales_data)

# 1. 使用group_by和summarise进行分组统计
product_summary <- sales_data %>%
  group_by(product) %>%
  summarise(
    total_sales = sum(sales_amount),
    avg_sales = mean(sales_amount),
    total_quantity = sum(quantity),
    avg_quantity = mean(quantity),
    transaction_count = n()
  )
print("产品汇总统计:")
print(product_summary)

# 2. 多维度分组(产品 × 地区)
product_region_summary <- sales_data %>%
  group_by(product, region) %>%
  summarise(
    total_revenue = sum(sales_amount),
    avg_revenue = mean(sales_amount)
  )
print("产品×地区销售统计:")
print(product_region_summary)

# 3. 使用aggregate进行分组统计
aggregate_result <- aggregate(sales_amount ~ product + region, 
                              data = sales_data, 
                              FUN = sum)
print("使用aggregate的产品×地区销售总额:")
print(aggregate_result)

# 4. 使用tapply进行分组统计
tapply_result <- tapply(sales_data$sales_amount, 
                        list(sales_data$product, sales_data$region), 
                        sum)
print("使用tapply的产品×地区销售矩阵:")
print(tapply_result)

# 5. 创建数据透视表
# 将产品作为行,月份作为列,销售总额作为值
sales_pivot <- dcast(sales_data, product ~ date, 
                     value.var = "sales_amount", 
                     fun.aggregate = sum)
print("产品销售月度透视表:")
print(sales_pivot)

# 6. 更复杂的透视:产品作为行,地区作为列,显示销售总额
region_pivot <- dcast(sales_data, product ~ region, 
                      value.var = "sales_amount", 
                      fun.aggregate = sum)
print("产品销售地区透视表:")
print(region_pivot)

# 7. 计算衍生指标(客单价)
product_metrics <- sales_data %>%
  group_by(product) %>%
  summarise(
    total_revenue = sum(sales_amount),
    total_units = sum(quantity),
    avg_unit_price = total_revenue / total_units  # 平均单价
  )
print("产品指标分析:")
print(product_metrics)

五、要点回顾

r 复制代码
# ==================== 要点回顾 ====================

# 1. 基础统计函数
# sum()   - 求和
# mean()  - 均值
# max()   - 最大值
# min()   - 最小值
# median()- 中位数
# var()   - 方差
# sd()    - 标准差
# quantile()- 分位数
# summary()- 综合统计

# 2. 分组统计家族
# tapply(值, 分组, 函数)     - 按因子分组
# aggregate(公式, 数据, 函数) - 灵活的分组
# by(数据, 分组, 函数)       - 对数据框分组
# split() + lapply()         - 拆分后应用函数

# 3. apply家族
# apply(数组, 方向, 函数)   - 矩阵/数据框
# lapply(列表, 函数)        - 返回列表
# sapply(列表, 函数)        - 简化结果

# 4. dplyr分组
# group_by() + summarise()   - 最常用的分组汇总
# group_by() + mutate()      - 添加分组统计列
# group_by() + filter()      - 按组条件筛选

# 5. 数据重塑
# melt()                     - 宽转长(reshape2)
# dcast()                    - 长转宽/透视表(reshape2)
# gather()                   - 宽转长(tidyr)
# spread()                   - 长转宽(tidyr)

# 选择建议:
# - 简单分组统计用 tapply() 或 aggregate()
# - 复杂数据操作(多列、多函数)用 dplyr 的 group_by() + summarise()
# - 需要生成报表/透视表时用 dcast()
# - 数据清洗时用 gather()/spread() 调整数据结构

以上内容涵盖了R语言数据计算与分组统计的核心知识点,每个函数都配有详细的注释和实际案例,便于理解和应用。

相关推荐
山居秋暝LS2 小时前
安装C++版opencv和opencv_contrib
开发语言·c++·opencv
lizhihai_992 小时前
股市学习心得—半导体12种核心材料
大数据·人工智能·学习
老陈说编程2 小时前
12. LangChain 6大核心调用方法:invoke/stream/batch同步异步全解析,新手也能轻松学会
开发语言·人工智能·python·深度学习·机器学习·ai·langchain
sakiko_2 小时前
UIKit学习笔记3-布局、滚动视图、隐藏或显示视图
前端·笔记·学习·objective-c·swift·uikit
014-code2 小时前
Java 并发中的原子类
java·开发语言·并发
alphageek82 小时前
Matlab linspace函数完全指南:从基础用法到进阶技巧
开发语言·其他·matlab
AI人工智能+电脑小能手2 小时前
【大白话说Java面试题】【Java基础篇】第29题:静态代理和动态代理的区别是什么
java·开发语言·后端·面试·代理模式
善恶怪客2 小时前
Java-数组和可变参数
java·开发语言
谭欣辰2 小时前
LCS(最长公共子序列)详解
开发语言·c++·算法