r语言查找是否存在空值_123.R简介和统计绘图

本文介绍R语言的统计分析能力和绘图实战,包括R的优势与缺点,R包的安装,以及数据类型、读写操作。通过实例演示了t-test、ANOVA和箱线图的使用,适合初学者学习。

123R简介和统计绘图

本节作者:刘永鑫 中国科学院遗传与发育生物学研究所;陈同 中国中医科学院

版本1.0.2,更新日期:2020年8月31日

本项目永久地址:https://github.com/YongxinLiu/MicrobiomeStatPlot ,本节目录 123R,包含R markdown(*.Rmd)、Word(*.docx)文档、测试数据和结果图表,欢迎广大同行帮忙审核校对、并提修改意见。提交反馈的三种方式:1. 公众号文章下方留言;2. 下载Word文档使用审阅模式修改和批注后,发送至微信(meta-genomics)或邮件(metagenome@126.com);3. 在Github中的Rmd文档直接修改并提交Issue。审稿人请在创作者登记表 https://www.kdocs.cn/l/c7CGfv9Xc 中记录个人信息、时间和贡献,以免专著发表时遗漏。

本文教程的源代码见123R简介和统计绘图.Rmd,实战代码详见R.Rmd。

为什么要学习R

61fa6d2da0f4e89a1a1c27f34d678d97.png
图. R常用图形 https://www.r-graph-gallery.com/

为什么选择R?
  • 多领域的资源, CRAN收录16170个R包 (20年9月1日),涵盖了统计学、经济学、生态学、进化生物学、生物信息学、物理、化学等多学科。

  • 跨平台, R可在多个主流操作系统下运行,包括Windows、MacOS和Linux。

  • 命令行驱动 R即时解释,输入命令,即可获得相应的结果,满足在绘图中及时修改的需要。

R语言优势
  • 统计分析能力突出,部分统计功能整合在R语言的底层,但大多数数据分析和可视化功能则以包(packages)的形式提供,资源极其丰富

  • R具有强大的数据可视化能力,高质量的图像输出工具以及多种现代绘图系统:

    如grid, lattice, ggplot2等

  • 扩展和开发能力,在R中可使用简洁的方式编写新的统计方法,甚至整合进其他语言编写的应用程序内。

    也可以编制自己的函数,或制作独立的统计分析包,快速实现新算法

  • 灵活,作为一种平台,方便与其他工具整合,实现数据分析流程化

  • 自由、免费、源代码开放,与多数商业统计软件相比,R是完全免费的,它囊括了在其他软件中尚不可用的且先进的统计计算例程(类似于函数,但含义更为丰富,如API接口),是一个可进行交互式数据分析和探索的高自由度平台

R语言缺点
  • 学习曲线陡峭:

    因为其功能丰富,导致对应帮助文件较多,而由独立贡献者编写的部分模块则较零散难以完全掌握,初学者刚开始与代码打交道,需要记住大量常用命令,无疑提高学习难度。

  • 需要大量计算资源:

    所有的待处理数据通常需要全部读入内存后才能处理,因此不适合分析超大规模的数据。

  • 运行速度稍慢:

    即时编译,效率约相当于C语言的1/20。

R排名

c88fe94d76d6f3b756f2300edc3a58c5.png
图. R语言世界使用率2020年8月排名 https://www.tiobe.com/tiobe-index/

目前R语言是世界上最受欢迎的10大语言之一。而且近些年始终处于上升阶段,截止2020年8月位于用户使用率榜单的第8位,较去年同期使用人数近乎翻倍。特别是在生命科学领域,被认为是使用频率最高的语言。其用户主要集中于专业领域,目前在移动设备、网页中使用率较低,但随着云端计算平台的发展,便携式移动端也是R未来的发展方向。

R语言统计绘图实战
R软件下载安装

R语言 https://www.r-project.org

Rstudio编程集成开发环境(IDE,Integrated Development Environment) https://www.rstudio.com

RStudio是一款R语言的IDE,R自带的环境操作较为复杂,而RStudio很好地解决了该问题,而且它还具有调试、可视化等功能,支持纯R脚本、Rmarkdown (脚本文档混排)、Shiny (交互式网络应用)等。

具体安装和配置步骤,详见:

  • 121个人电脑搭建微生物组分析平台(Win/Mac)

基于以下代码修改,为什么已经明确要求识别到的行索引为DataName,但还是老识别到DataName的后几行去了,不要识别到行名为DataValue,只识别DataName,并抓取DataName同一行且名称为Vg列、Id、Ib、IgIs列(都是浮点数)这五列数据做后续处理 import os import pandas as pd import matplotlib.pyplot as plt from pptx import Presentation from pptx.util import Pt, Inches import re from io import BytesIO import logging import chardet # 配置日志记录 logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') def process_csv_to_ppt(folder_path, output_pptx): """ 处理文件夹中的所有CSV文件,生成包含图表的PPT :param folder_path: CSV文件所在文件夹路径 :param output_pptx: 输出的PPT文件路径 :return: 处理是否成功 """ # 初始化PPT对象 prs = Presentation() # 获取所有CSV文件 csv_files = [f for f in os.listdir(folder_path) if f.lower().endswith('.csv')] if not csv_files: logging.error(f"在目录 {folder_path} 中没有找到CSV文件") return False logging.info(f"找到 {len(csv_files)} 个CSV文件") # 处理每个CSV文件 for file in csv_files: file_path = os.path.join(folder_path, file) file_base = os.path.splitext(file)[0] # 获取不带扩展名的文件名 logging.info(f"正在处理文件: {file}") try: # 步骤1: 查找包含"DataName"的行索引 header_row = find_dataname_row(file_path) if header_row is None: logging.warning(f" 跳过文件 {file}: 未找到'DataName'行") continue # 步骤2: 读取数据并提取所需列 df = read_csv_data(file_path, header_row) if df is None or df.empty: logging.warning(f" 文件 {file} 中没有有效数据") continue # 步骤3: 创建四个图表图像 images = create_plots(df, file_base) if not images or len(images) != 4: logging.warning(f" 无法为 {file} 创建4个图表") continue # 步骤4: 添加到PPT页面 add_slide_to_ppt(prs, images, file_base) logging.info(f" 成功添加 {file} 到PPT") except Exception as e: logging.error(f" 处理文件 {file} 时出错: {str(e)}") # 保存PPT文件 prs.save(output_pptx) logging.info(f"已生成PPT文件: {output_pptx}") return True def find_dataname_row(file_path): """ 查找包含'DataName'的行索引 :param file_path: CSV文件路径 :return: 找到的行索引(1-based),如果未找到返回None """ try: # 检测文件编码 with open(file_path, 'rb') as f: raw_data = f.read(10000) result = chardet.detect(raw_data) encoding = result['encoding'] if result['confidence'] > 0.7 else 'utf-8' # 读取文件内容 with open(file_path, 'r', encoding=encoding, errors='replace') as f: lines = [] for i, line in enumerate(f): if i >= 1000: # 最多检查200行 break lines.append(line.strip()) # 扫描寻找"DataName"行 for row_idx, line in enumerate(lines, 1): # 1-based索引 if "DataName" in line: return row_idx # 尝试不同大小写 for row_idx, line in enumerate(lines, 1): if "dataname" in line.lower(): return row_idx return None except Exception as e: logging.error(f" 查找'DataName'行出错: {str(e)}") return None def read_csv_data(file_path, header_row): """ 从CSV文件中读取数据,从DataName行开始 :param file_path: CSV文件路径 :param header_row: 'DataName'所在的行索引(1-based) :return: 包含所需列的DataFrame对象 """ try: # 检测文件编码 with open(file_path, 'rb') as f: raw_data = f.read(100000) result = chardet.detect(raw_data) encoding = result['encoding'] if result['confidence'] > 0.7 else 'utf-8' # 读取CSV文件,跳过DataName行之前的所有行 df = pd.read_csv( file_path, header=header_row - 1, # pandas使用0-based索引 encoding=encoding, engine='python', on_bad_lines='skip' ) # 标准化列名:移除特殊字符并转为小写 df.columns = [clean_column_name(col) for col in df.columns] # 检查所需列是否存在 required_cols = ['vg', 'id', 'ib', 'ig', 'is'] missing_cols = [col for col in required_cols if col not in df.columns] if missing_cols: logging.warning(f" 缺少列: {', '.join(missing_cols)}") logging.info(f" 实际列名: {df.columns.tolist()}") return None # 提取所需列并转换为数值类型 df = df[required_cols].copy() for col in df.columns: df[col] = pd.to_numeric(df[col], errors='coerce') # 移除空值无效行 df.dropna(inplace=True) # 移除全零行 df = df[(df[required_cols] != 0).any(axis=1)] # 检查是否有足够的数据点 if len(df) < 3: logging.warning(f" 有效数据点不足 ({len(df)})") return None return df except Exception as e: logging.error(f" 读取数据出错: {str(e)}") return None def clean_column_name(col): """ 清理列名:移除非字母数字字符并转为小写 :param col: 原始列名 :return: 清理后的列名 """ col_str = str(col).strip().lower() # 移除非字母数字字符(保留下划线) col_str = re.sub(r'[^a-z0-9_]', '', col_str) # 移除连续的下划线 col_str = re.sub(r'_+', '_', col_str) return col_str def create_plots(df, title_prefix): """ 为数据创建Vg vs Id、Ib、Ig、Is四个图表 :param df: 包含数据的DataFrame :param title_prefix: 图表标题前缀(文件名) :return: 四个图表图像的BytesIO对象列表 """ images = [] params = ['id', 'ib', 'ig', 'is'] # 需要绘图的四个参数 for param in params: try: # 创建图表 fig, ax = plt.subplots(figsize=(8, 5)) # 绘制数据:Vg为X轴,当前参数为Y轴 ax.plot(df['vg'], df[param], 'b-', linewidth=1.5, marker='o', markersize=4, label=f'{param.upper()} vs Vg') # 设置图表样式 ax.set_xlabel('Vg (V)', fontsize=12) ax.set_ylabel(f'{param.upper()} (A)', fontsize=12) ax.set_title(f'{title_prefix} - {param.upper()} vs Vg', fontsize=14) ax.grid(True, linestyle='--', alpha=0.6) ax.legend(loc='best') # 自动调整Y轴范围 y_min = df[param].min() y_max = df[param].max() # 处理全零或单值情况 if y_min == y_max: if y_min == 0: ax.set_ylim(-0.1, 0.1) else: ax.set_ylim(y_min * 0.9, y_min * 1.1) else: margin = (y_max - y_min) * 0.05 ax.set_ylim(y_min - margin, y_max + margin) # 科学计数法格式化(对于极小数或极大数) if abs(y_min) < 0.001 or abs(y_max) > 1000: ax.ticklabel_format(axis='y', style='sci', scilimits=(-3, 3)) # 保存到内存中的字节流 img_bytes = BytesIO() plt.savefig(img_bytes, format='png', dpi=150, bbox_inches='tight') img_bytes.seek(0) # 重置指针位置 images.append(img_bytes) # 清理图表资源 plt.close(fig) except Exception as e: logging.error(f" 创建 {param} 图表失败: {str(e)}") images.append(BytesIO()) # 添加空对象保持位置 plt.close('all') # 确保清理所有图表资源 return images def add_slide_to_ppt(prs, images, title_text): """ 将四个图表添加到PPT的一页 :param prs: Presentation对象 :param images: 四个图表图像的BytesIO对象 :param title_text: 幻灯片标题(文件名) """ # 添加空白幻灯片 slide = prs.slides.add_slide(prs.slide_layouts[6]) # 使用空白布局 # 添加标题 title = slide.shapes.add_textbox(Inches(0.5), Inches(0.25), Inches(9), Inches(0.5)) title_frame = title.text_frame p = title_frame.add_paragraph() p.text = title_text # 使用文件名作为标题 p.font.bold = True p.font.size = Pt(24) p.alignment = 1 # 居中 # 定义四个图表的位置 (2x2网格) positions = [ (Inches(0.5), Inches(1.0)), # 左上 (Inches(5.0), Inches(1.0)), # 右上 (Inches(0.5), Inches(4.0)), # 左下 (Inches(5.0), Inches(4.0)) # 右下 ] # 添加图表到幻灯片 for idx, img in enumerate(images): if img and img.getbuffer().nbytes > 0: # 检查图像是否有效 try: slide.shapes.add_picture( img, positions[idx][0], positions[idx][1], width=Inches(4.5), height=Inches(3.0) ) except Exception as e: logging.error(f" 添加图像到PPT失败: {str(e)}") else: logging.warning(f" 图表 {idx + 1} 无效或为空") if __name__ == "__main__": # 配置路径 # folder_path = r"C:\Users\x00708\PycharmProjects\mission\practice_from_work_data\zyh-画图\wafer21_npg_425" # 替换为CSV文件夹路径 # output_pptx = r"C:\Users\x00708\PycharmProjects\mission\practice_from_work_data\zyh-画图\result_npg.pptx" # 输出PPT文件路径 folder_path = r"C:\Users\x00708\PycharmProjects\mission\practice_from_work_data\zyh-画图\11.4_425_wafer21" # 替换为CSV文件夹路径 output_pptx = r"C:\Users\x00708\PycharmProjects\mission\practice_from_work_data\zyh-画图\result_11.4.pptx" # 输出PPT文件路径 # 处理文件 success = process_csv_to_ppt(folder_path, output_pptx) if success: print(f"处理完成! PPT已保存至: {output_pptx}") else: print("处理过程中遇到问题,请检查日志输出")
最新发布
11-06
你提供的 `submit()` 函数是一个 Vue 3 Composition API 中的表单提交函数,主要用于在用户选择两个仓库(入库出库)后,通过 `props.close()` 返回数据。代码逻辑清晰,但我们可以从**健壮性、可读性、可维护性**角度进一步优化。 --- ## ✅ 优化后的代码 ```ts function submit() { if (!in_repertory_id.value) { HsMessage.error('请选择入库仓库'); return; } if (!out_repertory_id.value) { HsMessage.error('请选择出库仓库'); return; } // 从仓库列表中查找名称 const inRepertory = repertory_list.value?.find( (item) => item.id === in_repertory_id.value ); const outRepertory = repertory_list.value?.find( (item) => item.id === out_repertory_id.value ); const in_repertory_name = inRepertory?.name ?? '未知仓库'; const out_repertory_name = outRepertory?.name ?? '未知仓库'; console.log('submit', { in_repertory_id: in_repertory_id.value, in_repertory_name, out_repertory_id: out_repertory_id.value, out_repertory_name, }); props.close?.({ type: 'confirm', data: { in_repertory_id: in_repertory_id.value, in_repertory_name, out_repertory_id: out_repertory_id.value, out_repertory_name, }, }); } ``` --- ## 🔍 代码解释 ### ✅ 1. 参数校验部分 ```ts if (!in_repertory_id.value) { HsMessage.error('请选择入库仓库'); return; } ``` - 使用 `value` 说明 `in_repertory_id` 是一个 `ref`。 - 如果未选择,弹出错误提示并终止函数。 ### ✅ 2. 从仓库列表中查找仓库名称 ```ts const inRepertory = repertory_list.value?.find( (item) => item.id === in_repertory_id.value ); ``` - 使用可选链 `?.` 防止 `repertory_list.value` 为 `null` 或 `undefined` 报错。 - 使用 `find()` 查找匹配的仓库对象。 ### ✅ 3. 使用空值合并运算符设置默认值 ```ts const in_repertory_name = inRepertory?.name ?? '未知仓库'; ``` - 如果 `inRepertory` 或 `name` 不存在,返回默认值 `'未知仓库'`。 - 使用 `??` 而不是 `||`,避免 `0` 或 `''` 被误判为空值。 ### ✅ 4. 调用 `props.close()` 提交数据 ```ts props.close?.({ type: 'confirm', data: { in_repertory_id: in_repertory_id.value, in_repertory_name, out_repertory_id: out_repertory_id.value, out_repertory_name, }, }); ``` - 使用可选调用 `?.` 防止 `props.close` 未定义时报错。 - 将数据封装为对象传递给父组件。 --- ## 🧪 示例数据结构 ```ts const repertory_list = ref([ { id: 1, name: '仓库A' }, { id: 2, name: '仓库B' }, ]); const in_repertory_id = ref(1); const out_repertory_id = ref(2); ``` 输出结果: ```js { in_repertory_id: 1, in_repertory_name: '仓库A', out_repertory_id: 2, out_repertory_name: '仓库B' } ``` --- ## ✅ 总结 | 特性 | 说明 | |------|------| | `ref.value` | 获取响应式变量的值 | | `?.` | 可选链,防止空值报错 | | `??` | 空值合并,安全设置默认值 | | `find()` | 从数组中查找符合条件的元素 | | `props.close?.()` | 安全调用函数,防止未定义报错 | --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值