R语言200习题训练(带答案)(四)——函数的定义与调用

此部分内容会每日更新,包括但不限于基础知识,进阶知识,数据处理,图表展示,数据分析实战,机器学习算法等~ !!!
本人统计学硕士在读,想在2024年完成sql、python、R语言、stata、matlab等软件的复盘和巩固,目前在做统计学知识和R语言的复习~
后续考虑出相关视频进行讲解说明,请大家持续点赞+收藏+关注哈,大家一起沟通交流~

1.4 函数定义与调用(约10道习题)

习题1:
题目:编写一个函数,输入两个数字,返回它们的和。

习题1解答:

sum_numbers <- function(num1, num2) {
  return(num1 + num2)
}
# 调用函数
result <- sum_numbers(3, 5)
print(result)  # 输出: 8

习题2:
题目:创建一个函数,该函数接受一个字符串作为参数,并返回该字符串的长度。

习题2解答:

get_string_length <- function(str) {
  return(length(str))
}
# 调用函数
str_len <- get_string_length("Hello")
print(str_len)  # 输出: 5

习题3:
题目:编写一个函数,用于计算一个给定列表的平均值。
习题3解答:

average_of_list <- function(lst) {
  if (length(lst) > 0) {
    return(mean(lst))
  } else {
    return(NA)  # 或者可以抛出错误或返回其他默认值
  }
}
# 调用函数
avg <- average_of_list(c(1, 2, 3, 4))
print(avg)  # 输出: 2.5

习题4:
题目:创建一个函数,该函数接受一个整数作为参数,并返回其是否为偶数的布尔值。

习题4解答:

is_even_number <- function(num) {
  return(num %% 2 == 0)
}
# 调用函数
is_even <- is_even_number(4)
print(is_even)  # 输出: TRUE

习题5:
题目:编写一个函数,它接受一个字符串和一个整数作为参数,返回字符串中每n个字符后的子字符串。

习题5解答:

get_substring_every_n <- function(str, n) {
  if (n <= 0) {
    stop("n must be a positive integer")
  }
  substrings <- seq(1, nchar(str), by = n)
  return(substr(str, substrings, substrings + n - 1))
}
# 调用函数
substrs <- get_substring_every_n("abcdefgh", 3)
print(substrs)  # 输出: "abc" "def" "gh"

习题6:
题目:创建一个函数,该函数接受两个列表作为参数,并返回它们合并后的新列表。

习题6解答:

merge_lists_function <- function(lst1, lst2) {
  return(c(lst1, lst2))
}
# 调用函数
merged_list <- merge_lists_function(c(1, 2, 3), c(4, 5, 6))
print(merged_list)  # 输出: 1 2 3 4 5 6

习题7:
题目:编写一个函数,它接受一个列表和一个元素作为参数,如果元素在列表中,则返回True,否则返回False。
习题7解答:

element_in_list_func <- function(lst, elem) {
  return(elem %in% lst)
}
# 调用函数
is_in_list <- element_in_list_func(c(1, 2, 3), 2)
print(is_in_list)  # 输出: TRUE

习题8:
题目:创建一个函数,该函数接受一个数字列表和一个目标数字作为参数,返回列表中第一个大于目标数字的元素的索引。
习题8解答:

index_of_first_greater <- function(lst, target) {
  for (i in seq_along(lst)) {
    if (lst[i] > target) {
      return(i)
    }
  }
  return(NULL)  # 如果没有找到大于target的元素,返回NULL
}
# 调用函数
index <- index_of_first_greater(c(1, 3, 5, 7), 4)
print(index)  # 输出: 2

习题9:
题目:编写一个函数,用于计算一个给定数字列表的乘积。
习题9解答:

product_of_list_func <- function(lst) {
  if (length(lst) > 0) {
    return(prod(lst))
  } else {
    return(1)  # 空列表的乘积定义为1
  }
}
# 调用函数
prod_val <- product_of_list_func(c(2, 3, 4))
print(prod_val)  # 输出: 24

习题10:
题目:创建一个函数,该函数接受一个数字列表作为参数,并返回列表中的最大和最小值的元组。

习题10解答:

max_min_of_list_func <- function(lst) {
  if (length(lst) > 0) {
    return(c(min(lst), max(lst)))
  } else {
    return(c(NA, NA))  # 或者可以抛出错误或返回其他默认值
  }
}
# 调用函数
max_min <- max_min_of_list_func(c(7, 1, 9, 3, 5))
print(max_min)  # 输出: 1 9

函数的参数传递与返回值处理

习题11:
题目:编写一个函数,它接受两个参数(a和b),将a的值增加5并返回新的a值,同时保持b的值不变。
习题11解答:

increase_a <- function(a, b) {
  a <- a + 5
  return(list(a = a, b = b))
}

# 调用函数
result <- increase_a(3, 4)
print(result$a)  # 输出: 8
print(result$b)  # 输出: 4

习题12:
题目:创建一个函数,该函数接受三个参数,并返回它们的和。确保函数能够正确处理不同数据类型(如整数和浮点数)的输入。
习题12解答:

sum_three_numbers <- function(x, y, z) {
  return(x + y + z)
}

# 调用函数
sum_result <- sum_three_numbers(1, 2.5, 3)
print(sum_result)  # 输出: 6.5

习题13:
题目:编写一个函数,它接受一个列表和一个整数作为参数,返回一个新的列表,其中包含原始列表中所有大于该整数的元素。
习题13解答:

filter_greater_than <- function(lst, threshold) {
  return(lst[lst > threshold])
}

# 调用函数
filtered_list <- filter_greater_than(c(1, 3, 5, 2, 4), 3)
print(filtered_list)  # 输出: 3 5 4

习题14:
题目:创建一个函数,该函数接受两个列表作为参数,并返回一个新的列表,其中包含两个列表中所有不重复的元素。
习题14解答:

union_unique <- function(lst1, lst2) {
  return(unique(c(lst1, lst2)))
}
# 调用函数
unique_list <- union_unique(c(1, 2, 3), c(2, 3, 4, 5))
print(unique_list)  # 输出: 1 2 3 4 5

习题15:
题目:编写一个函数,它接受一个列表和一个函数作为参数,对列表中的每个元素应用该函数,并返回一个新的列表,其中包含应用函数后的结果。
习题15解答:

apply_function_to_list <- function(lst, func) {
  return(lapply(lst, func))
}

# 调用函数
squared_list <- apply_function_to_list(c(1, 2, 3), function(x) x^2)
print(squared_list)  # 输出: 1 4 9

习题16:
题目:创建一个函数,该函数接受一个字符串和一个函数作为参数,将函数应用于字符串中的每个字符,并返回一个新的字符串,其中包含应用函数后的结果。
习题16解答:

apply_function_to_string <- function(str, func) {
  return(paste(sapply(strsplit(str, ""), func), collapse = ""))
}

# 调用函数
upper_case_str <- apply_function_to_string("hello", toupper)
print(upper_case_str)  # 输出: HELLO

习题17:
题目:编写一个函数,它接受一个数字和一个函数作为参数,如果数字是偶数,则调用函数并返回结果;如果数字是奇数,则返回原始数字。
习题17解答:

conditional_apply <- function(num, func) {
  if (num %% 2 == 0) {
    return(func(num))
  } else {
    return(num)
  }
}
# 调用函数
double_if_even <- function(x) x * 2
result <- conditional_apply(4, double_if_even)
print(result)  # 输出: 8

习题18:
题目:创建一个函数,该函数接受两个函数作为参数,并返回一个新的函数,该新函数依次调用这两个函数并返回它们的结果。
习题18解答:

compose_functions <- function(func1, func2) {
  return(function(x) func2(func1(x)))
}

# 调用函数
add_then_multiply <- compose_functions(function(x) x + 1, function(x) x * 2)
result <- add_then_multiply(3)
print(result)  # 输出: 8

习题19:
题目:编写一个函数,它接受一个列表和一个函数作为参数,返回一个新的列表,其中包含原始列表中满足函数条件的元素。
习题19解答:

filter_by_condition <- function(lst, condition_func) {
  return(lst[sapply(lst, condition_func)])
}

# 调用函数
is_positive <- function(x) x > 0
positive_numbers <- filter_by_condition(c(-1, 2, -3, 4, -5), is_positive)
print(positive_numbers)  # 输出: 2 4

习题20:
题目:创建一个函数,该函数接受一个字典和一个函数作为参数,对字典中的每个值应用该函数,并返回一个新的字典,其中包含应用函数后的结果。
习题20解答:

apply_function_to_dict <- function(dict, func) {
  return(lapply(dict, function(value) func(value)))
}

# 调用函数
double_values <- function(value) value * 2
doubled_dict <- apply_function_to_dict(list(a = 1, b = 2, c = 3), double_values)
print(doubled_dict)  # 输出: a 2 b 4 c 6

函数的调试与优化(约10道习题)

请注意,函数的调试与优化通常需要实际编写和运行代码,并根据出现的错误或性能问题进行调整。因此,以下题目更侧重于识别潜在问题和提出优化策略,而不是直接的代码实现。

习题21:
题目:描述在R中调试函数时可能遇到的常见错误类型,并给出至少三种调试策略。
在R中调试函数时,可能会遇到以下几种常见的错误类型:

  1. 语法错误:如拼写错误、缺少括号、错误的函数名等。
  2. 运行时错误:例如,尝试访问不存在的变量、数组越界、调用不存在的函数等。
  3. 逻辑错误:代码可以正常运行,但结果不符合预期,可能是因为算法逻辑不正确或条件判断有误。
  4. 性能问题:代码可以正确运行,但处理大型数据集时效率低下,可能是因为使用了不合适的算法或数据结构。

调试策略:

  1. 使用print语句:在代码的关键部分添加print语句,输出变量的值,帮助定位问题所在。
  2. 使用调试器:RStudio提供了一个强大的调试器,可以设置断点、单步执行、查看变量值等。
  3. 简化问题:尝试使用更小的数据集或简化问题的复杂度,以便更容易地定位错误。
  4. 查阅文档和社区资源:查看相关函数的文档,了解正确的用法;在R社区(如Stack Overflow)搜索类似问题,看是否有现成的解决方案。

习题22:
题目:分析以下函数,找出可能存在的逻辑错误或性能问题,并提出优化建议:

my_function <- function(x) {
  result <- 0
  for (i in 1:length(x)) {
    result <- result + x[i]
  }
  return(result)
}

函数my_function的目的是计算向量x中所有元素的和。从逻辑上看,这个函数是正确的,但它没有利用R的向量化操作,这可能会导致性能问题,特别是在处理大型数据集时。

优化建议:

  1. 使用向量化操作:可以直接使用sum函数来计算向量的和,而不需要循环。
my_function <- function(x) {
  return(sum(x))
}
  1. 检查输入:在函数中增加对输入x的检查,确保它是数值向量。
my_function <- function(x) {
  if (!is.numeric(x) || !is.vector(x)) {
    stop("Input must be a numeric vector.")
  }
  return(sum(x))
}

习题23:
题目:考虑一个函数,它在处理大型数据集时运行缓慢。提出至少两种可能的优化方法。

处理大型数据集时,函数运行缓慢可能是因为使用了不高效的算法或数据结构。以下是两种可能的优化方法:

  1. 使用向量化操作:R的向量化操作通常比循环更快,因为它们是在底层用C或Fortran实现的。尽量避免使用显式的for循环,而是利用R的向量化特性。

  2. 数据分块处理:如果数据集太大,无法一次性加载到内存中,可以考虑将数据分块处理。每次只加载和处理一部分数据,然后保存结果,再继续处理下一部分数据。

习题24:
题目:编写一个函数,该函数包含一个明显的逻辑错误。解释错误的原因,并提出修复建议。

my_function <- function(x) {
  if (x > 0) {
    return("Positive")
  } else {
    return("Negative")
  }
}

# 测试函数
result <- my_function(0)
print(result)  # 输出应该是"Negative"或"Positive",但这里什么都不会输出,因为0既不大于0也不小于0

错误原因:函数没有处理x等于0的情况,导致当x为0时,函数不会返回任何值。

修复建议:在else语句之前添加一个条件来处理x等于0的情况。

my_function <- function(x) {
  if (x > 0) {
    return("Positive")
  } else if (x < 0) {
    return("Negative")
  } else {
    return("Zero")
  }
}

习题25:
题目:分析以下函数,找出可能导致内存泄漏的代码段,并提出解决方案。

假设函数如下:

leaky_function <- function(data) {
  result <- list()
  for (i in 1:length(data)) {
    temp <- data.frame(data[i])  # 创建新的数据框,但没有释放内存
    result <- c(result, temp)    # 将数据框添加到列表中,进一步消耗内存
  }
  return(result)
}

在这个函数中,每次循环都会创建一个新的data.frame对象temp,并将其添加到result列表中。这些临时对象如果没有被及时清理,可能会导致内存泄漏。

解决方案:

  1. 避免在循环中创建大型对象:如果可能的话,尝试在循环外部创建对象,并在循环内部更新它。

  2. 使用lapplysapply代替循环:这些函数可以更高效地处理列表和向量,并且通常不需要显式地创建临时对象。

习题26:
题目:描述在R中如何使用profvis包来分析和优化函数的性能。

在R中,profvis包是一个非常有用的工具,用于分析和优化函数的性能。profvis提供了一个交互式的可视化界面,识别代码中的瓶颈和优化机会。

以下是如何使用profvis包来分析和优化函数性能的步骤:

  1. 首先,需要安装并加载profvis包。如果还没有安装,可以通过运行install.packages("profvis")来安装。然后,通过library(profvis)来加载包。

  2. 使用profvis函数包装想要分析的代码。例如,如果有一个名为my_function的函数,可以这样使用profvis

library(profvis)
profvis({
  # 调用函数
  result <- my_function(your_arguments)
})

习题27:
题目:假设有一个函数,它在处理向量输入时效率很低。提出优化方法,并写代码示例对比。

假设有一个函数slow_vector_function,它在处理向量输入时效率很低。这个函数可能是通过循环来遍历向量的每个元素并进行某种计算。一个常见的优化方法是使用向量化操作来替代循环,因为R的向量化操作通常比循环更快。

以下是一个示例:

# 假设的原始低效函数
slow_vector_function <- function(vec) {
  result <- numeric(length(vec))
  for (i in 1:length(vec)) {
    result[i] <- vec[i]^2 + 2 * vec[i] + 1
  }
  return(result)
}

# 优化后的函数,使用向量化操作
fast_vector_function <- function(vec) {
  return(vec^2 + 2 * vec + 1)
}

# 创建一个向量用于测试
test_vector <- 1:10000

# 对比执行时间
system.time({ slow_result <- slow_vector_function(test_vector) })
system.time({ fast_result <- fast_vector_function(test_vector) })

# 检查结果是否相同
all.equal(slow_result, fast_result)

在这个例子中,slow_vector_function使用了一个for循环来计算每个元素的平方、乘以2然后加1。而fast_vector_function则直接对整个向量进行了这些操作,利用了R的向量化特性。通过比较执行时间,可以看到优化后的函数fast_vector_function运行得更快。同时,我们也使用all.equal来确认两个函数的结果是否相同。

  • 32
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值