5 Star 21 Fork 15

zhjx19/tidyverse120

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
玩转数据处理120题.Rmd 33.25 KB
一键复制 编辑 原始数据 按行查看 历史
zhjx19 提交于 2024-05-26 15:47 . 更新到2023版
title author date header-includes output
**玩转数据120题——R语言tidyverse版本(2023版)**
张敬信
`r Sys.Date()`
\usepackage{ctex}
pdf_document urlcolor linkcolor
latex_engine
xelatex
blue
red
```{r, setup, include=FALSE} knitr::opts_chunk$set( warning = FALSE, message = FALSE) ``` ```{r include=FALSE} options(tibble.print_max = 6, tibble.print_min = 6) library(showtext) showtext_auto() ``` **关于作者**: - 张敬信,哈尔滨商业大学,数学与应用数学,副教授 - 热爱学习,热爱编程,热爱 R 语言 - 我的代表作《R 语言编程:基于 tidyverse》已于 2023 年 2 月正式上市,京东、天猫、当当等各大平台有售: ```{r echo=FALSE, out.width="55%", fig.align="center"} knitr::include_graphics("MyRbook.png") ``` - 也有免费学习资源:[课件和鲸在线版(可调试代码)](https://www.heywhale.com/mw/project/641dc0d4feb4fe02b2ce72f7) ,[知乎交流平台](https://www.zhihu.com/column/c_1375580759047237632),欢迎您的阅读品鉴、交流讨论! - 该书的 QQ 读者1群、2群:875664831、222427909, 交流、答疑,欢迎您的加入! \newpage **玩转数据120题**来自刘早起的 *Pandas 进阶修炼 120 题*,涵盖了数据处理、计算、可视化等常用操作,希望通过 120 道精心挑选的习题吃透 pandas. 后来,中山大学博士陈熹提供了 R 语言版本。我[^ft1][^ft2][^ft3]再来个更能体现 R 语言最新技术的 tidyverse 版本。 关于**更新版**:感谢`@鼠大米`对部分解法不够tidyverse的题目,提供了新解法(再加上我稍微修正),主要是加入更好用的新函数`slice_*()`。2023年,部分题目又做了一些改进。 [^ft1]: 我的 Github: https://github.com/zhjx19 [^ft2]: 我的知乎: https://www.zhihu.com/people/huc_zhangjingxin [^ft3]: 我的和鲸项目(包含本文件的在线可调试版):https://www.heywhale.com/home/user/profile/5d4a42a636e903002c0e0c66/project - 先加载包: ```{r} library(tidyverse) ``` ## Part I 入门 ### 题目1(创建数据框):将下面的字典创建为DataFrame ```data = {"grammer": ["Python","C","Java","GO",np.nan,"SQL","PHP","Python"], "score": [1,2,np.nan,4,5,6,7,10]}``` **难度:**$\star$ **代码及运行结果:** ```{r} df = tibble( grammer = c("Python","C","Java","GO", NA,"SQL","PHP","Python"), score = c(1,2,NA,4,5,6,7,10)) df ``` - **补充:**按行录入式创建数据框 ```{r} df = tribble( ~ grammer, ~ score, "Python", 1, "C", 2, "Java", NA, "GO", 4, NA, 5, "SQL", 6, "PHP", 7, "Python", 10) ``` ### 问题2(筛选行):提取含有字符串"Python"的行 **难度:**$\star$ **代码及运行结果:** ```{r echo=TRUE} df %>% filter(grammer == "Python") ``` ### 题目3(查看列名):输出df的所有列名 **难度:**$\star$ **代码及运行结果:** ```{r} names(df) ``` ### 题目4(修改列名):修改第2列列名为"popularity" **难度:**$\star\star$ **代码及运行结果:** ```{r} df = df %>% rename(popularity = score) df ``` ### 题目5(统计频数):统计grammer列中每种编程语言出现的次数 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% count(grammer) ``` ### 题目6(缺失值处理):将空值用上下值的平均值填充 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} df = df %>% mutate(popularity = zoo::na.approx(popularity)) df ``` **注:** tidyr包提供了`fill()`函数,可以用前值或后值插补缺失值。 ### 题目7(筛选行):提取popularity列中值大于3的行 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% filter(popularity > 3) ``` ### 题目8(数据去重):按grammer列进行去重 **难度:** $\star \star$ **代码及运行结果:** ```{r} df %>% distinct(grammer, .keep_all = TRUE) ``` ### 题目9(数据计算):计算popularity列平均值 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% summarise(avg = mean(popularity)) ``` ### 题目10(格式转换):将grammer列转换为序列 **难度:**$\star$ **代码及运行结果:** ```{r} df %>% pull(grammer) # 或者df$grammer ``` **注:** R从数据框中提取出来就是字符向量。 ### 题目11(数据保存):将数据框保存为Excel **难度:**$\star\star$ **代码及运行结果:** ```{r} writexl::write_xlsx(df, "data/filename.xlsx") ``` ### 题目12(数据查看):查看数据的行数列数 **难度:**$\star$ **代码及运行结果:** ```{r} dim(df) ``` ### 题目13(筛选行):提取popularity列值大于3小于7的行 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% filter(popularity > 3 & popularity < 7) ``` ### 题目14(调整列位置):交互两列的位置 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% select(popularity, grammer) ``` **注:** 可配合`everything()`放置“其余列”,更强大的调整列位置的函数是dplyr1.0将提供的`relocate()`. ### 题目15(筛选行):提取popularity列最大值所在的行 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% slice_max(popularity, n = 1) # 或者 # df %>% # filter(popularity == max(popularity)) ``` ### 题目16(查看数据):查看最后几行数据 **难度:**$\star$ **代码及运行结果:** ```{r} df %>% slice_tail(n = 6) # 或者tail(df, 6) ``` **注:** 此外,`dplyr`包还提供了`slice_head()`查看前`n`行或前某比例的行,`slice_sample()`随机查看`n`行或某比例的行。 ### 题目17(修改数据):删除最后一行数据 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% slice(-n()) ``` ### 题目18(修改数据):添加一行数据:"Perl", 6 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% add_row(grammer = "Perl", popularity = 6) # 或者 # df %>% # bind_rows(tibble(grammer = "Perl", popularity = 6)) ``` ### 题目19(数据整理):对数据按popularity列值从到大到小排序 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% arrange(-popularity) ``` **注:** 默认从小到大排序。 ### 题目20(字符统计):统计grammer列每个字符串的长度 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% mutate(strlen = str_length(grammer)) ``` ## Part II 基础 ### 题目21(读取数据):读取本地Excel数据 **难度:**$\star$ **代码及运行结果:** ```{r} df = readxl::read_xlsx("data/21-50数据.xlsx") df ``` ### 题目22(查看数据):查看df数据的前几行 **难度:**$\star$ **代码及运行结果:** ```{r} head(df, 5) ``` ### 题目23(数据计算):将salary列数据转换为最大值与最小值的平均值 **难度:**$\star\star\star\star$ **代码及运行结果:** ```{r} df = df %>% separate(salary, into = c("low", "high"), sep = "-") %>% # sep="-"也可以省略 mutate(salary = (parse_number(low) + parse_number(high)) * 1000 / 2) %>% select(-c(low, high)) df ``` 或者来个高级的,用正则表达式提取数字,定义做计算的函数,再`purrr::map_dbl`做循环计算: ```{r eval=FALSE} calc = function(x) sum(as.numeric(unlist(x))) * 1000 / 2 df %>% mutate(salary = map_dbl(str_extract_all(salary, "\\d+"), calc)) # 结果同上(略) ``` ### 题目24(分组汇总):根据学历分组,并计算平均薪资 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} df %>% group_by(education) %>% summarise(salary_avg = mean(salary)) ``` ### 题目25(时间转换):将createTime列转换为"月-日" **难度:**$\star\star\star$ **代码及运行结果:** ```{r} library(lubridate) df %>% mutate(createTime = str_sub(createTime, 6, 10)) ``` ### 题目26(查看数据):查看数据结构信息 **难度:**$\star$ **代码及运行结果:** ```{r} glimpse(df) # 或者用str() object.size(df) # 查看对象占用内存 ``` ### 题目27(查看数据):查看数据汇总信息 **难度:**$\star$ **代码及运行结果:** ```{r} summary(df) ``` ### 题目28(修改列):新增一列将salary离散化为三水平值 **难度:**$\star\star\star\star$ **代码及运行结果:** ```{r} df = df %>% mutate(class = case_when( salary >= 0 & salary < 5000 ~ "低", salary >= 5000 & salary < 20000 ~ "中", .default = "高")) df ``` - 或者用`cut()`函数: ```{r eval=FALSE} df %>% mutate(class = cut(salary, breaks = c(0,5000,20000,Inf), labels = c("低", "中", "高"), right = FALSE)) ``` - 或者用`sjmisc`包中的`rec()`,和SPSS的重新编码一样强大。 ```{r eval=FALSE} df %>% mutate(class = sjmisc::rec(salary, rec = "min:5000 = 低; 5000:20000 = 中; 20000:max = 高")) ``` ### 题目29(数据整理):按salary列对数据降序排列 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% arrange(-salary) ``` ### 题目30(筛选行):提取第33行数据 **难度:**$\star$ **代码及运行结果:** ```{r} df %>% slice(33) # 或者df[33,] ``` ### 题目31(数据计算):计算salary列的中位数 **难度:**$\star$ **代码及运行结果:** ```{r} df %>% summarise(med = median(salary)) # 或者median(df$salary) ``` ### 题目32(数据可视化):绘制salary的频率分布直方图 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} df %>% ggplot(aes(salary)) + geom_histogram(bins = 10, fill = "steelblue", color = "black") ``` ### 题目33(数据可视化):绘制salary的频率密度曲线图 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} df %>% ggplot(aes(salary)) + geom_density(color = "red") ``` ### 题目34(数据删除):删除最后一列class **难度:**$\star$ **代码及运行结果:** ```{r} df %>% select(-class) # 或者 # df %>% # select(-last_col()) # 同last_col(0) ``` ### 题目35(数据操作):将df的第1列与第2列合并为新的一列 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% unite("newcol", 1:2, sep = " ") ``` ### 题目36(数据操作):将education列与第salary列合并为新的一列 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% unite("newcol", c(education, salary), sep = " ") ``` ### 题目37(数据计算):计算salary最大值与最小值之差 **难度:**$\star\star$ **代码及运行结果:** ```{r} max(df$salary) - min(df$salary) ``` 或者用 ```{r} df %>% summarise(range = max(salary) - min(salary)) ``` ### 题目38(数据操作):将第一行与最后一行拼接 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% slice(1, n()) ``` ### 题目39(数据操作):将第8行添加到末尾 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% bind_rows(slice(., 8)) ``` ### 题目40(查看数据):查看每一列的数据类型 **难度:**$\star$ **代码及运行结果:** ```{r} glimpse(df) # 或者用str() ``` ### 题目41(数据操作):将createTime列设置为行索引 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% distinct(createTime, .keep_all = TRUE) %>% column_to_rownames("createTime") ``` **注:** 行索引不允许有重复,所以先做了一步去重。 ### 题目42(数据创建):生成一个和df长度相同的随机数数据框 **难度:**$\star\star$ **代码及运行结果:** ```{r} df1 = tibble(rnums = sample(10, nrow(df), replace = TRUE)) df1 ``` ### 题目43(数据连接):将上面生成的数据框与df按列合并 **难度:**$\star\star$ **代码及运行结果:** ```{r} df = bind_cols(df, df1) df ``` **注:**实际上,42,43题应该合并成一个题,这是数据操作中最常规的修改列: ```{r} df %>% mutate(rnums = sample(10, n(), replace = TRUE)) ``` ### 题目44(修改列):生成新列new为salary列减去随机数列 **难度:**$\star\star$ **代码及运行结果:** ```{r} df = df %>% mutate(new = salary - rnums) df ``` ### 题目45(检查缺失值):检查数据中是否含有任何缺失值 **难度:**$\star\star$ **代码及运行结果:** ```{r} anyNA(df) anyNA(df$salary) ``` **注:** naniar包提供了更强大的探索缺失值及缺失模式的函数,其中`miss_var_summary()`和`miss_case_summary()`可检查各列和各行缺失情况。 ### 题目46(类型转换):将salary列的类型转换为浮点数 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% mutate(rnums = as.double(rnums)) ``` ### 题目47(数据汇总):计算salary列大于10000的次数 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} df %>% count(salary > 10000) ``` 或者用 ```{r} df %>% summarise(n = sum(salary > 10000)) ``` ### 题目48(统计频数):查看每种学历出现的次数 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% count(education) ``` ### 题目49(数据汇总):查看education列共有几种学历 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% distinct(education) ``` ### 题目50(筛选行):提取salary与new列之和大于60000的最后3行 **难度:**$\star\star\star\star$ **代码及运行结果:** ```{r} df %>% filter(salary + new > 60000) %>% slice_tail(n = 3) ``` ## Part III 提高 ### 题目51(读取数据):使用绝对路径读取本地Excel数据 **难度:**$\star$ **代码及运行结果:** ```{r} df = readxl::read_xls("data/51-80数据.xls") df ``` ### 题目52(查看数据):查看数据框的前3行 **难度:**$\star$ **代码及运行结果:** ```{r} head(df, 3) ``` **说明:**当前数据不包含缺失值,接下来关于缺失值的题目53-56,改用自带的 `starwars`数据演示。 ### 题目53(查看缺失值):查看每列数据缺失值情况 **难度:**$\star\star$ **代码及运行结果:** ```{r} map_int(starwars, ~ sum(is.na(.x))) ``` **注:** 也可以用`naniar`包中的 `miss_var_summary()`函数。 ### 题目54(查看缺失值):查看日期列含有缺失值的行 **难度:**$\star\star$ **代码及运行结果:** ```{r} starwars %>% filter(is.na(hair_color)) ``` ### 题目55(查看缺失值):查看每列缺失值在哪些行 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} map(starwars, ~ which(is.na(.x))) ``` ### 题目56(缺失值处理):删除所有存在缺失值的行 **难度:**$\star\star$ **代码及运行结果:** ```{r} starwars %>% drop_na() ``` **注:** 若要删除某些列包含缺失值的行,提供列名即可。 ### 题目57(数据可视化):绘制收盘价的折线图 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% ggplot(aes(日期, `收盘价(元)`)) + geom_line(color = "red") ``` ### 题目58(数据可视化):同时绘制开盘价与收盘价 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} df %>% select(日期, `开盘价(元)`, `收盘价(元)`) %>% pivot_longer(-日期, names_to = "type", values_to = "price") %>% ggplot(aes(日期, price, color = type)) + geom_line() ``` **注:** 为了自动添加图例,先对数据做了宽变长转换。 ### 题目59(数据可视化):绘制涨跌幅的直方图 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% ggplot(aes(`涨跌幅(%)`)) + geom_histogram(fill = "steelblue", color = "black") ``` ### 题目60(数据可视化):让直方图更细致 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% ggplot(aes(`涨跌幅(%)`)) + geom_histogram(bins = 50, fill = "steelblue", color = "black") ``` ### 题目61(数据创建):用df的列名创建数据框 **难度:**$\star\star$ **代码及运行结果:** ```{r} tibble(Name = names(df)) ``` ### 题目62(异常值处理):输出所有换手率不是数字的行 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% mutate(`换手率(%)` = parse_number(`换手率(%)`)) %>% filter(is.na(`换手率(%)`)) ``` ### 题目63(异常值处理):输出所有换手率为--的行 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% filter(`换手率(%)` == "--") ``` ### 题目64(数据操作):重置df的行号 **难度:**$\star$ **代码及运行结果:** ```{r} rownames(df) = NULL # R中无行号就是数字索引 ``` ### 题目65(异常值处理):删除所有换手率为非数字的行 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% mutate(`换手率(%)` = parse_number(`换手率(%)`)) %>% filter(!is.na(`换手率(%)`)) ``` ```{r} library(lubridate) df = df %>% mutate(across(4:18, as.numeric), 日期 = as_date(日期)) df ``` ### 题目66(数据可视化):绘制换手率的密度曲线 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% ggplot(aes(`换手率(%)`)) + geom_density() ``` ### 题目67(数据计算):计算前一天与后一天收盘价的差值 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% mutate(delta = `收盘价(元)` - lag(`收盘价(元)`)) %>% select(日期, `收盘价(元)`, delta) ``` ### 题目68(数据计算):计算前一天与后一天收盘价的变化率 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% mutate(change = (`收盘价(元)` - lag(`收盘价(元)`)) / `收盘价(元)`) %>% select(日期, `收盘价(元)`, change) ``` ### 题目69(数据操作):设置日期为行索引 **难度:**$\star$ **代码及运行结果:** ```{r} df %>% column_to_rownames("日期") %>% # 将从tibble变成data.frame head() ``` ### 题目70(数据计算):对收盘价做步长为5的滑动平均 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} library(slider) df %>% mutate(avg_5 = slide_dbl(`收盘价(元)`, mean, na.rm = TRUE, .before = 2, .after = 2)) %>% select(日期, `收盘价(元)`, avg_5) ``` ### 题目71(数据计算):对收盘价做步长为5的滑动求和 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} df %>% mutate(sum_5 = slide_dbl(`收盘价(元)`, sum, na.rm = TRUE, .before = 2, .after = 2)) %>% select(日期, `收盘价(元)`, sum_5) ``` ### 题目72(数据可视化):将收盘价及其5日均线、20日均线绘制在同一个图上 **难度:**$\star\star\star\star$ **代码及运行结果:** ```{r} df %>% mutate(avg_5 = slide_dbl(`收盘价(元)`, mean, na.rm = TRUE, .before = 2, .after = 2), avg_20 = slide_dbl(`收盘价(元)`, mean, na.rm = TRUE, .before = 10, .after = 9)) %>% pivot_longer(c(`收盘价(元)`, avg_5, avg_20), names_to = "type", values_to = "price") %>% ggplot(aes(日期, price, color = type)) + geom_line() ``` ### 题目73(数据重采样):按周为采样规则,计算一周收盘价最大值 **难度:**$\star\star\star\star$ **代码及运行结果:** ```{r} library(tsibble) weekmax = df %>% group_by(weeks = yearweek(日期)) %>% # 年-周 slice_max(`收盘价(元)`) # 默认n = 1 weekmax ``` ### 题目74(数据可视化):绘制重采样数据与原始数据 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} weekmax %>% ggplot(aes(weeks, `收盘价(元)`)) + geom_line(color = "red") + geom_line(data = df, aes(日期, `收盘价(元)`), color = "steelblue") ``` ### 题目75(数据操作):将数据往后移动5天 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} df %>% mutate(across(4:18, ~ lag(.x, 5))) ``` **注:**这是批量做后移,单个变量做后移用`mutate(var = lag(var, 5)`即可。 ### 题目76(数据操作):将数据往前移动5天 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} df %>% mutate(across(4:18, ~ lead(.x, 5))) ``` ### 题目77(数据操作):计算开盘价的累积平均 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} rlt = df %>% mutate(累积平均 = cummean(`开盘价(元)`)) %>% select(日期, `开盘价(元)`, 累积平均) rlt ``` ### 题目78(数据计算):绘制开盘价的累积平均与原始数据的折线图 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} rlt %>% pivot_longer(-日期, names_to = "类型", values_to = "价格") %>% ggplot(aes(日期, 价格, color = 类型)) + geom_line() ``` ### 题目79(数据计算):计算布林指标 **难度:**$\star\star\star\star$ **代码及运行结果:** ```{r} boll = df %>% mutate(avg_20 = slide_dbl(`收盘价(元)`, mean, na.rm = TRUE, .before = 10, .after = 9), sd_20 = slide_dbl(`收盘价(元)`, sd, na.rm = TRUE, .before = 10, .after = 9), up = avg_20 + 2 * sd_20, down = avg_20 - 2 * sd_20) %>% select(日期, `收盘价(元)`, avg_20, up, down) boll %>% slice_sample(n = 10) ``` ### 题目80(数据可视化):绘制布林曲线 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} boll %>% pivot_longer(-日期, names_to = "类型", values_to = "价格") %>% ggplot(aes(日期, 价格, color = 类型)) + geom_line() ``` ## Part VI 数据生成 ### 题目81(加载查看包):加载并查看tidyverse包版本 **难度:**$\star$ **代码及运行结果:** ```{r} # 得是首次加载 library(tidyverse) ``` ### 题目82(生成随机数):生成20个0~100的随机数,创建数据框 **难度:**$\star$ **代码及运行结果:** ```{r} set.seed(123) # 保证结果出现 df1 = tibble(nums = sample(100, 20)) df1 ``` ### 题目83(生成等差数):生成20个0~100固定步长的数,创建数据框 **难度:**$\star$ **代码及运行结果:** ```{r} df2 = tibble(nums = seq(0, 99, by = 5)) df2 ``` ### 题目84(生成指定分布随机数):生成20个标准正态分布的随机数,创建数据框 **难度:**$\star$ **代码及运行结果:** ```{r} set.seed(123) df3 = tibble(nums = rnorm(20, 0, 1)) df3 ``` ### 题目85(合并数据):将df1, df2, df3按行合并为新数据框 **难度:**$\star$ **代码及运行结果:** ```{r} bind_rows(df1, df2, df3) ``` ### 题目86(合并数据):将df1, df2, df3按列合并为新数据框 **难度:**$\star$ **代码及运行结果:** ```{r} df = bind_cols(df1, df2, df3) df ``` ### 题目87(查看数据):查看df所有数据的最小值、25%分位数、中位数、75%分位数、最大值 **难度:**$\star\star$ **代码及运行结果:** ```{r} unlist(df) %>% summary() ``` ### 题目88(修改列名):修改列名为col1, col2, col3 **难度:**$\star$ **代码及运行结果:** ```{r} df = df %>% set_names(str_c("col", 1:3)) df ``` **注:**若只修改个别列名,用`rename(newname = oldname)`. ### 题目89(数据操作):提取在第1列中而不在第2列中的数 **难度:**$\star\star$ **代码及运行结果:** ```{r} setdiff(df$col1, df$col2) ``` ### 题目90(数据操作):提取在第1列和第2列出现频率最高的三个数字 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} tibble(nums = c(df$col1, df$col2)) %>% count(nums, sort = TRUE) %>% slice(1:3) ``` ### 题目91(数据操作):提取第1列可以整除5的数的位置 **难度:**$\star\star$ **代码及运行结果:** ```{r} which(df$col1 %% 5 == 0) ``` - 选取满足条件的索引,通常用途还是用来选出满足条件的行,不兜圈子做法: ```{r} df %>% filter(col1 %% 5 == 0) ``` ### 题目92(数据计算):计算第1列的1阶差分 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% mutate(diff1 = col1 - lag(col1)) ``` **注:**若只是要数值,用`diff(df$col1)`即可。 ### 题目93(数据操作):将col1, col2, col3三列顺序颠倒 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% select(rev(names(df))) ``` **注:**更灵活的调整列序,dplyr 1.0提供的`relocate()`函数。 ### 题目94(数据操作):提取第一列位置在1,10,15的数 **难度:**$\star$ **代码及运行结果:** ```{r} df[c(1,10,15), 1] ``` ### 题目95(数据操作):查找第一列的局部最大值位置 **难度:**$\star\star\star\star$ **代码及运行结果:** ```{r} df %>% mutate(diff = sign(col1 - lag(col1)) + sign(col1 - lead(col1))) which(rlt$diff == 2) ``` - 不兜圈子做法: ```{r} df %>% mutate(diff = sign(col1 - lag(col1)) + sign(col1 - lead(col1))) %>% filter(diff == 2) ``` ### 题目96(数据计算):按行计算df每一行的均值 **难度:**$\star\star$ **代码及运行结果:** ```{r} rowMeans(df) # 或者apply(df, 1, mean) # 或者 df %>% mutate(row_avg = pmap_dbl(., ~ mean(c(...)))) ``` ### 题目97(数据计算):对第二列计算步长为3的移动平均值 *难度:**$\star\star\star$ **代码及运行结果:** ```{r} df %>% mutate(avg_3 = slide_dbl(col2, mean, .before = 1, .after = 1)) ``` ### 题目98(数据计算):按第三列值的大小升序排列 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% arrange(col3) ``` ### 题目99(数据操作):按第一列大于50的数修改为"高" **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% mutate(col1 = ifelse(col1 > 50, "高", col1)) ``` ### 题目100(数据计算):计算第一列与第二列的欧氏距离 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} (df$col1 - df$col2) ^ 2 |> sum() |> sqrt() ``` ## Part V 高级 ### 题目101(数据读取):从csv文件中读取指定数据:读取前10行, positionName和salary列 **难度:**$\star\star$ **代码及运行结果:** ```{r} read_csv("data/数据1_101-120涉及.csv", n_max = 10, col_select = c(positionName, salary)) ``` ### 题目102(数据读取):从csv文件中读取数据,将薪资大于10000的改为"高" **难度:**$\star\star$ **代码及运行结果:** ```{r} df = read_csv("data/数据2_101-120涉及.csv") %>% mutate(薪资水平 = if_else(薪资水平 > 10000, "高", "低")) ``` ### 题目103(数据操作):从df中对薪资水平每隔20行进行抽样 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% slice(seq(1, n(), by = 20)) ``` ### 题目104(数据操作):取消使用科学记数法 **难度:**$\star\star$ **代码及运行结果:** ```{r} set.seed(123) df = tibble(val = runif(10) ^ 10) # 三位小数 df %>% mutate(val = scales::number(val, accuracy = 0.001)) # 科学记数法 df %>% mutate(val = scales::scientific(val, 2)) ``` ### 题目105(数据操作):将上一题的数据转换为百分数 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} df %>% mutate(val = scales::percent(val, 0.01)) ``` ### 题目106(数据操作):查找上一题数据中第3大值的行号 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} order(df$val, decreasing = TRUE)[3] ``` - 不兜圈子做法: ```{r} df %>% arrange(-val) %>% slice(3) ``` ### 题目107(数据操作):反转df的行 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% slice(rev(1:n())) # 或者df[nrow(df):1,] ``` ### 题目108(数据连接:全连接):根据多列匹配合并数据,保留df1和df2的观测 **难度:**$\star\star$ **代码及运行结果:** ```{r} df1 = tibble( key1 = c("K0","K0","K1","K2"), key2 = c("K0","K1","K0","K1"), A = str_c('A', 0:3), B = str_c('B', 0:3)) df1 df2 = tibble( key1 = c("K0","K1","K1","K2"), key2 = str_c("K", rep(0,4)), C = str_c('C', 0:3), D = str_c('D', 0:3)) df2 df1 %>% full_join(df2, by = c("key1", "key2")) ``` ### 题目109(数据连接:左连接):根据多列匹配合并数据,只保留df1的观测 **难度:**$\star\star$ **代码及运行结果:** ```{r} df1 %>% left_join(df2, by = c("key1", "key2")) ``` **注:**dplyr包还提供了右连接:`right_join()`,内连接:`inner_join()`,以及用于过滤的连接:半连接:`semi_join()`,反连接:`anti_join()`. ### 题目110(数据处理):再次读取数据1并显示所有列 **难度:**$\star\star$ **代码及运行结果:** ```{r} df = read_csv("data/数据1_101-120涉及.csv") glimpse(df) ``` ### 题目111(数据操作):查找secondType与thirdType值相等的行号 **难度:**$\star\star$ **代码及运行结果:** ```{r} which(df$secondType == df$thirdType) ``` - 不兜圈子: ```{r} df %>% filter(secondType == thirdType) ``` ### 题目112(数据操作):查找薪资大于平均薪资的第三个数据 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} df %>% filter(salary > mean(salary)) %>% slice(3) ``` ### 题目113(数据操作):将上一题数据的salary列开根号 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% mutate(salary_sqrt = sqrt(salary)) %>% select(salary, salary_sqrt) ``` ### 题目114(数据操作):将上一题数据的linestation列按_拆分 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} df %>% separate(linestaion, into = c("line", "station"), sep = "_", remove = FALSE) %>% select(linestaion, line, station) ``` **注:**正常需要先按“;”分割,再分别按“-”分割。 ### 题目115(数据查看):查看上一题数据一共有多少列 **难度:**$\star$ **代码及运行结果:** ```{r} ncol(df) ``` ### 题目116(数据操作):提取industryField列以"数据"开头的行 **难度:**$\star\star$ **代码及运行结果:** ```{r} df %>% filter(str_detect(industryField, "^数据")) ``` ### 题目117(数据分组汇总):以salary score和positionID做数据透视表 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} df %>% group_by(positionId) %>% summarise(salary_avg = mean(salary), score_avg = mean(score)) ``` ### 题目118(数据分组汇总):同时对salary、score两列进行汇总计算 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} df %>% summarise(across(c(salary, score), list(sum=sum, mean=mean, min=min), .names = "{.col}_{.fn}")) ``` **注:**若要分组再这样汇总,前面加上`group_by(var)`即可。 ### 题目119(数据分组汇总):同时对不同列进行不同的汇总计算:对salary求平均,对score求和 **难度:**$\star\star\star$ **代码及运行结果:** ```{r} df %>% summarise(salary_avg = mean(salary), score_sum = sum(score)) ``` **注:**若要分组再这样汇总,前面加上`group_by(var)`即可。 ### 题目120(数据分组汇总):计算并提取平均薪资最高的区 **难度:**$\star\star\star\star$ **代码及运行结果:** ```{r} df %>% group_by(district) %>% summarise(salary_avg = mean(salary)) %>% slice_max(salary_avg) # 默认n = 1 ```
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
R
1
https://gitee.com/zhjx19/tidyverse120.git
[email protected]:zhjx19/tidyverse120.git
zhjx19
tidyverse120
tidyverse120
main

搜索帮助