如何使用Python计算数据排名?rank排序方案

1.使用pandas的rank()方法是python中计算数据排名的核心方案。它适用于series和dataframe,支持多种重复值处理方式(method=’average’/’min’/’max’/’first’/’dense’),并可控制升序或降序排列(ascending参数)以及缺失值处理(na_option参数)。2.针对重复值处理策略,’average’取平均排名,’min’取最小排名,’max’取最大排名,’first’按出现顺序,’dense’生成无空缺的紧密排名。3.对于缺失值,默认保留为nan,也可通过na_option设置为排在顶部或底部。4.多列复合排名需先排序再创建辅助列,而分组排名可通过groupby().rank()实现。5.实际应用时应明确排名目的、考虑数据分布、验证结果合理性,并结合业务逻辑选择合适的参数组合以避免常见误区。

如何使用Python计算数据排名?rank排序方案

在Python中,要计算数据排名,最直接且功能强大的工具无疑是Pandas库。它提供了一个rank()方法,能够灵活地处理各种排名需求,包括对重复值(ties)的不同处理方式。这个方法不仅高效,而且非常符合数据分析师的日常操作习惯,可以说,它是进行数据排名时的首选方案。

如何使用Python计算数据排名?rank排序方案

解决方案

使用Pandas库的rank()方法是Python中计算数据排名的核心方案。无论是Series还是DataFrame,这个方法都能派上用场。它允许你指定如何处理相同数值(ties),以及排名的升序或降序。

import pandas as pdimport numpy as np# 示例数据data = {    'score': [90, 85, 90, 78, 95, 85, np.nan, 92],    'name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve', 'Frank', 'Grace', 'Heidi']}df = pd.DataFrame(data)# 1. 对Series进行排名(默认method='average',即平均排名)# 相同分数的会取平均排名,例如90分有两人,排名2和3,则都取(2+3)/2=2.5df['rank_avg'] = df['score'].rank(ascending=False) # 降序排名,分数越高排名越靠前print("--- Average Rank ---")print(df[['name', 'score', 'rank_avg']])# 2. 对Series进行排名,method='min'(最小排名)# 相同分数的都取最小排名,例如90分有两人,排名2和3,则都取2df['rank_min'] = df['score'].rank(method='min', ascending=False)print("n--- Min Rank ---")print(df[['name', 'score', 'rank_min']])# 3. 对Series进行排名,method='max'(最大排名)# 相同分数的都取最大排名,例如90分有两人,排名2和3,则都取3df['rank_max'] = df['score'].rank(method='max', ascending=False)print("n--- Max Rank ---")print(df[['name', 'score', 'rank_max']])# 4. 对Series进行排名,method='first'(按出现顺序排名)# 相同分数的按它们在原始数据中出现的顺序来排名df['rank_first'] = df['score'].rank(method='first', ascending=False)print("n--- First Rank ---")print(df[['name', 'score', 'rank_first']])# 5. 对Series进行排名,method='dense'(紧密排名)# 相同分数的排名相同,下一个不同的分数排名紧接其后,没有空缺df['rank_dense'] = df['score'].rank(method='dense', ascending=False)print("n--- Dense Rank ---")print(df[['name', 'score', 'rank_dense']])# 6. 处理缺失值(NaN)# 默认情况下,NaN会被排除在排名之外,并返回NaN。# 可以通过na_option参数控制:'keep'(保留NaN并赋予其排名NaN,默认),'top'(NaN排在最前面),'bottom'(NaN排在最后面)df['rank_na_top'] = df['score'].rank(ascending=False, na_option='top')print("n--- Rank with NaN at Top ---")print(df[['name', 'score', 'rank_na_top']])# 7. 对DataFrame进行多列排名(例如,先按分数排名,分数相同再按姓名排名)# 注意:DataFrame的rank方法通常用于按轴(axis)排名,或者需要对每一列独立排名。# 如果是多列组合排名,通常需要先进行排序,然后创建辅助列,或者使用更复杂的逻辑。# 这里演示一个简单的DataFrame级别rank,它会独立对每一列进行排名。print("n--- DataFrame Rank (column-wise) ---")print(df.rank(ascending=False))# 如果需要按多列进行复合排名,通常是先排序再用cumcount或row_number# 例如:先按分数降序,分数相同按姓名升序df_sorted = df.sort_values(by=['score', 'name'], ascending=[False, True])df_sorted['compound_rank'] = np.arange(1, len(df_sorted) + 1) # 简单地赋予一个顺序排名print("n--- Compound Rank (score desc, name asc) ---")print(df_sorted[['name', 'score', 'compound_rank']])

Pandas rank() 方法:深入理解核心参数与应用场景

说实话,每次遇到数据排名这事儿,我脑子里首先跳出来的就是Pandas的rank()方法,它简直是为这个场景量身定制的。但别以为rank()就那么简单地一用到底,它背后藏着几个小玄机,特别是处理那些“打平”的数据时,就得费点心思了。

立即学习“Python免费学习笔记(深入)”;

如何使用Python计算数据排名?rank排序方案

rank()方法的核心参数主要围绕着如何处理“重复值”(ties)以及排名的方向。

method 参数: 这是最关键的参数,决定了如何处理相同数值的排名。

如何使用Python计算数据排名?rank排序方案'average' (默认值): 这是最常用的方式,它会将所有相同数值的排名取平均值。比如,如果有三个人都考了90分,他们理论上应该排第2、3、4名,那么每个人都会得到 (2+3+4)/3 = 3.0 的排名。这种方法在很多统计分析中都很常见,因为它能保持排名的“连续性”。'min': 所有相同数值都取它们中最小的排名。如果三个人都考了90分,他们都会排第2名。这在需要强调“至少达到”某个排名时很有用。'max': 所有相同数值都取它们中最大的排名。同样三个人,都会排第4名。这在需要强调“不超过”某个排名时可能更有意义。'first': 相同数值的排名会根据它们在原始数据中出现的顺序来决定。先出现的就排在前面。这在需要保持原始数据顺序,且排名是次要考虑因素时很有用,比如在展示一个排行榜时,同分选手按录入时间先后排序。'dense': 这种方法会赋予相同数值相同的排名,并且下一个不同的数值的排名会紧接着上一个,中间不会跳过任何数字。例如,排名可能是1, 2, 2, 3, 4, 4。它生成的是一个“紧密”的排名序列,没有空缺。

ascending 参数: 决定排名是升序还是降序。

True (默认值): 数值越小,排名越靠前(例如,1, 2, 3…)。False: 数值越大,排名越靠前(例如,第一名是最高分)。这在通常的“排行榜”场景中非常常见。

na_option 参数: 处理缺失值(NaN)。

'keep' (默认值): 缺失值在排名结果中仍然是NaN。它们不参与排名计算。'top': 缺失值会被排在所有非缺失值的前面(即,如果ascending=True,它们会是最小的排名;如果ascending=False,它们会是最大的排名)。'bottom': 缺失值会被排在所有非缺失值的后面。

应用场景思考:选择哪个method真的取决于你的业务需求。比如,在体育比赛中,并列第一通常用'min';在学术排名中,为了区分度,可能会用'average';而如果只是想看有多少个不同的等级,'dense'就很有用。我个人觉得,在实际项目中,最容易踩坑的就是对method参数的理解不够深入,导致排名结果和预期大相径庭。所以,每次用之前,我都会花点时间确认一下,这个排名到底想表达什么。

处理排名中重复值(Ties)的策略与Python实现

处理重复值,也就是我们常说的“打平”或者“并列”的情况,是数据排名中一个绕不开的话题。Pandas的rank()方法通过其method参数提供了非常优雅的解决方案,但除了Pandas,Python生态系统里还有其他工具也能处理这类问题,比如NumPy和SciPy。

正如前面提到的,Pandas rank()方法的method参数就是专门用来解决这个问题的:'average', 'min', 'max', 'first', 'dense'。每一种方法都代表了一种处理并列的策略。

'average' (平均排名): 这是最“公平”的方式,它将并列的元素分配一个平均的排名。如果你不确定该用哪种方法,这通常是个不错的起点。

import pandas as pdscores = pd.Series([100, 90, 90, 80, 70])print(scores.rank(ascending=False, method='average'))# 输出:0    1.0  (100)#       1    2.5  (90)#       2    2.5  (90)#       3    4.0  (80)#       4    5.0  (70)

这里90分并列,原应是第2、3名,取平均值2.5。

'min' (最小排名): 所有并列的元素都取它们中最小的那个排名。这在某些场景下很有用,比如你只想知道“至少能排到第几”。

print(scores.rank(ascending=False, method='min'))# 输出:0    1.0#       1    2.0#       2    2.0#       3    4.0#       4    5.0

90分并列,都取第2名。

'max' (最大排名): 所有并列的元素都取它们中最大的那个排名。

print(scores.rank(ascending=False, method='max'))# 输出:0    1.0#       1    3.0#       2    3.0#       3    4.0#       4    5.0

90分并列,都取第3名。

'first' (按出现顺序): 这是一种“打破僵局”的方法。如果数值相同,那么在原始数据中出现得更早的元素会获得更高的排名。

print(scores.rank(ascending=False, method='first'))# 输出:0    1.0#       1    2.0#       2    3.0#       3    4.0#       4    5.0

第一个90分排第2,第二个90分排第3。

'dense' (紧密排名): 这种方法不会在排名中留下空隙。如果有并列,它们会获得相同的排名,但下一个非并列的元素会紧接着获得下一个整数排名。

print(scores.rank(ascending=False, method='dense'))# 输出:0    1.0#       1    2.0#       2    2.0#       3    3.0#       4    4.0

90分并列都排第2,80分直接排第3。

Scipy rankdata 的补充:在某些情况下,你可能处理的是纯粹的NumPy数组,或者需要更底层的控制。scipy.stats.rankdata函数提供了与Pandas rank()类似的功能,它也能处理重复值,并且其method参数与Pandas的对应关系非常明确。

from scipy.stats import rankdataimport numpy as nparr = np.array([100, 90, 90, 80, 70])# 默认是'average'print("Scipy rankdata (average):", rankdata(-arr)) # 负号是为了实现降序排名,因为rankdata默认是升序# 输出:Scipy rankdata (average): [1.  2.5 2.5 4.  5. ]print("Scipy rankdata (min):", rankdata(-arr, method='min'))# 输出:Scipy rankdata (min): [1. 2. 2. 4. 5.]print("Scipy rankdata (dense):", rankdata(-arr, method='dense'))# 输出:Scipy rankdata (dense): [1. 2. 2. 3. 4.]

可以看到,scipy.stats.rankdata在处理逻辑上与Pandas非常相似,可以作为Pandas之外的一个备选方案,尤其是在NumPy为主的环境中。

总的来说,理解这些method参数的细微差别至关重要。选择哪种策略,完全取决于你希望排名如何反映数据的真实情况,以及它将如何被后续的分析或决策所使用。没有绝对的“最佳”方法,只有“最适合”你当前场景的方法。

数据排名在实际业务分析中的常见误区与最佳实践

在实际业务分析中,数据排名看似简单,但如果不注意一些细节,很容易掉进坑里,导致分析结果偏颇,甚至影响决策。我个人在处理大量数据排名时,总结了一些常见的误区和我认为的最佳实践。

常见误区:

忽略缺失值(NaN)的影响: 很多人在排名时,直接就对含有NaN的列进行操作,但没有明确处理na_option。默认情况下,Pandas的rank()会将NaN的排名也设为NaN,这意味着这些数据点直接从排名序列中“消失”了。但在某些场景下,缺失可能本身就代表一种“最差”的表现(比如用户没有完成某个任务,所以没有分数),这时将其排在最后(na_option='bottom')可能更符合业务逻辑。反之,如果缺失代表“尚未开始”或“不适用”,那么保留为NaN或将其排在“顶部”可能更合理。

method参数的理解偏差: 这是我见过最多的问题。比如,你可能希望“并列第一”就是第一名,结果却得到了一个平均排名。或者,你希望排名是连续的,结果却因为并列而出现了跳跃。不理解'average', 'min', 'max', 'first', 'dense'这几种方法的具体含义和它们在业务上的潜在影响,是导致排名结果与预期不符的根本原因。

不考虑数据分布的特点: 排名是将数值数据转化为序数数据。如果原始数据分布非常不均匀(比如大部分值都集中在一个很小的范围内,只有少数几个异常值),那么简单的排名可能无法很好地反映出数据内部的真实差异。例如,如果99%的用户得分都在80-85之间,只有一个人得了100分,那么这个100分的用户排名会非常靠前,但其他用户的排名可能就显得过于密集,区分度不高。这时,可能需要考虑分箱(binning)或者使用百分位数(percentile)而非绝对排名。

将排名与百分位数混淆: 排名通常是基于1到N的整数序列,表示一个元素在有序集合中的位置。而百分位数(percentile)则表示一个值低于或等于某个百分比的数据点的比例。例如,排名第10不等于处于第10个百分位。理解两者的区别,并根据分析目的选择合适的度量方式非常重要。Pandas的rank(pct=True)可以计算百分比排名,这在很多场景下比绝对排名更有意义。

不考虑性能问题: 对于非常大的数据集,直接对整个DataFrame进行rank()操作可能会比较耗时。如果只需要对部分数据或特定分组进行排名,可以考虑使用groupby().rank()来提高效率,或者在数据预处理阶段就进行降采样。

最佳实践:

明确排名目的: 在开始排名之前,先问自己:这个排名是为了什么?是为了找出最好的几个?还是为了评估相对位置?或者只是为了对数据进行排序以便后续处理?不同的目的会影响你选择的methodna_option

可视化排名分布: 对排名结果进行简单的可视化,比如直方图或箱线图,可以帮助你快速发现排名是否符合预期,是否存在异常情况。

对重复值处理方式进行说明: 在报告或展示排名结果时,务必清晰地说明你采用了哪种重复值处理方式(method参数),以及为什么选择它。这能增加你分析结果的透明度和可信度。

考虑分组排名: 在许多业务场景中,我们需要的不是全局排名,而是基于某个或多个维度(如地区、产品类别、时间段)的组内排名。Pandas的groupby()结合rank()是实现这一目标的强大工具。

# 示例:按部门分组,计算每个部门内部的员工绩效排名df_emp = pd.DataFrame({    'department': ['HR', 'IT', 'HR', 'IT', 'HR', 'IT'],    'performance_score': [85, 92, 90, 88, 75, 95],    'employee': ['A', 'B', 'C', 'D', 'E', 'F']})df_emp['dept_rank'] = df_emp.groupby('department')['performance_score'].rank(ascending=False, method='dense')print("n--- Grouped Rank ---")print(df_emp.sort_values(by=['department', 'dept_rank']))

结合业务知识进行验证: 排名结果出来后,不要立刻就采信。用你的业务知识去“校验”一下,看看排在前面和后面的数据点是否符合直觉。如果出现反常,很可能是你的排名逻辑或者数据本身有问题。

总之,数据排名不是一个简单的函数调用,它是一个涉及数据理解、业务逻辑和统计方法选择的综合过程。保持批判性思维,多问几个为什么,才能确保你的排名分析真正有价值。

以上就是如何使用Python计算数据排名?rank排序方案的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1364001.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
高效合并多个NumPy .npz文件教程
上一篇 2025年12月14日 03:44:37
高效合并多个NumPy NPZ文件教程
下一篇 2025年12月14日 03:44:45

相关推荐

  • composer require-dev和require有什么不同_Composer Require与Require-Dev区别解析

    require用于声明项目运行必需的依赖,如框架、数据库组件和第三方SDK,这些包会随项目部署到生产环境;2. require-dev用于声明仅在开发和测试阶段需要的工具,如PHPUnit、PHPStan、Faker等,不会默认部署到生产环境;3. 安装时composer install根据环境决定…

    2026年5月10日
    1000
  • Matplotlib 地图中多类型图例的创建与优化

    Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化

    本教程旨在解决matplotlib地图可视化中,如何在一个图例中同时展示颜色块(如区域分类)和自定义标记(如特定兴趣点)的问题。文章详细介绍了当传统`patch`对象无法正确显示标记时,如何利用`matplotlib.lines.line2d`创建标记图例句柄,并将其与颜色块图例句柄合并,从而生成一…

    2026年5月10日 用户投稿
    100
  • 利用海象运算符简化条件赋值:Python教程与最佳实践

    本文旨在探讨Python中海象运算符(:=)在条件赋值场景下的应用。通过对比传统if/else语句与海象运算符,以及条件表达式,分析海象运算符在简化代码、提高可读性方面的优势与局限性。并通过具体示例,展示如何在列表推导式等场景下合理使用海象运算符,同时强调其潜在的复杂性及替代方案,帮助开发者更好地掌…

    2026年5月10日
    100
  • Debian syslog性能优化技巧有哪些

    提升Debian系统syslog (通常基于rsyslog)性能,关键在于精简配置和高效处理日志。以下策略能有效优化日志管理,提升系统整体性能: 精简配置,高效加载: 在rsyslog配置文件中,仅加载必要的输入、输出和解析模块。 使用全局指令设置日志级别和格式,避免不必要的处理。 自定义模板: 创…

    2026年5月10日
    000
  • c++中的SFINAE技术是什么_c++模板编程中的SFINAE原理与应用

    SFINAE 是“替换失败不是错误”的原则,指模板实例化时若参数替换导致错误,只要存在其他合法候选,编译器不报错而是继续重载决议。它用于条件启用模板、类型检测等场景,如通过 decltype 或 enable_if 控制函数重载,实现类型特征判断。尽管 C++20 引入 Concepts 简化了部分…

    2026年5月10日
    000
  • RichHandler与Rich Progress集成:解决显示冲突的教程

    在使用rich库的`richhandler`进行日志输出并同时使用`progress`组件时,可能会遇到显示错乱或溢出问题。这通常是由于为`richhandler`和`progress`分别创建了独立的`console`实例导致的。解决方案是确保日志处理器和进度条组件共享同一个`console`实例…

    2026年5月10日
    000
  • 理解编程指令:当结果正确,但实现方式不符要求时

    本文探讨了在编程实践中,即使程序输出了正确的结果,但若其实现方式未能严格遵循既定指令,仍可能被视为“不正确”的问题。我们将通过具体示例,对比直接求和与累加求和两种实现策略,强调理解和遵守编程规范的重要性,以确保代码的健壮性、可维护性及符合项目要求。 在软件开发过程中,我们经常会遇到这样的情况:编写的…

    2026年5月10日
    000
  • Golang goroutine与channel调试技巧

    使用go run -race检测数据竞争,结合runtime.NumGoroutine监控协程数量,通过pprof分析阻塞调用栈,利用select超时避免永久阻塞,有效排查goroutine泄漏、死锁和数据竞争问题。 Go语言的goroutine和channel是并发编程的核心,但它们也带来了调试上…

    2026年5月10日
    000
  • 使用 Jupyter Notebook 进行探索性数据分析

    Jupyter Notebook通过单元格实现代码与Markdown结合,支持数据导入(pandas)、清洗(fillna)、探索(matplotlib/seaborn可视化)、统计分析(describe/corr)和特征工程,便于记录与分享分析过程。 Jupyter Notebook 是进行探索性…

    2026年5月10日
    000
  • php常量怎么用_PHP常量(define/const)定义与使用方法

    PHP中可通过define函数和const关键字定义常量,用于存储不可变值。define适用于全局作用域,支持动态名称和条件定义,如define(‘SITE_NAME’, ‘MyWebsite’);const在编译时生效,语法简洁但限制多,只能在类或全…

    2026年5月10日
    000
  • 网站标题关键词更新后,搜索引擎为何仍显示旧标题?

    网站标题更新后,搜索引擎为何显示旧标题? 网站SEO优化中,站长常修改网站标题关键词,期望搜索结果显示自定义标题。然而,即使更新标签、meta keywords、meta description和结构化数据中的name属性后,搜索结果仍显示旧标题,这令人费解。本文将对此进行解释。 问题:站长修改了网…

    2026年5月10日
    100
  • Python命令怎样使用profile分析脚本性能 Python命令性能分析的基础教程

    使用Python的cProfile模块分析脚本性能最直接的方式是通过命令行执行python -m cProfile your_script.py,它会输出每个函数的调用次数、总耗时、累积耗时等关键指标,帮助定位性能瓶颈;为进一步分析,可将结果保存为文件python -m cProfile -o ou…

    2026年5月10日
    000
  • 如何插入查询结果数据_SQL插入Select查询结果方法

    如何插入查询结果数据_SQL插入Select查询结果方法如何插入查询结果数据_SQL插入Select查询结果方法如何插入查询结果数据_SQL插入Select查询结果方法如何插入查询结果数据_SQL插入Select查询结果方法

    使用INSERT INTO…SELECT语句可高效插入数据,通过NOT EXISTS、LEFT JOIN、MERGE语句或唯一约束避免重复;表结构不一致时可通过别名、类型转换、默认值或计算字段处理;结合存储过程可提升可维护性,支持参数化与动态SQL。 将查询结果数据插入到另一个表中,可以…

    2026年5月10日 用户投稿
    000
  • Discord.py 交互按钮超时与持久化解决方案

    本教程旨在解决Discord.py中交互按钮在一段时间后出现“This Interaction Failed”错误的问题。我们将深入探讨视图(View)的超时机制,并提供通过正确设置timeout参数以及利用bot.add_view()方法实现按钮持久化的具体方案,确保您的机器人交互功能稳定可靠,即…

    2026年5月10日
    000
  • Python递归函数追踪与性能考量:以序列打印为例

    本文深入探讨了Python中一种递归打印序列元素的方法,并着重演示了如何通过引入缩进参数来有效追踪递归函数的执行流程和参数变化。通过实际代码示例,文章揭示了递归调用可能带来的潜在性能开销,特别是对调用栈空间的需求,以及Python默认递归深度限制可能导致的错误,为读者提供了理解和优化递归算法的实用见…

    2026年5月10日
    000
  • python中zip函数详解 python多序列压缩zip函数应用场景

    zip函数的应用场景包括:1) 同时遍历多个序列,2) 合并多个列表的数据,3) 数据分析和科学计算中的元素运算,4) 处理csv文件,5) 性能优化。zip函数是一个强大的工具,能够简化代码并提高处理多个序列时的效率。 在Python中,zip函数是一个非常有用的工具,它能够将多个可迭代对象打包成…

    2026年5月10日
    000
  • 谷歌浏览器如何截图 谷歌浏览器页面截图技巧

    谷歌浏览器如何截图 谷歌浏览器页面截图技巧谷歌浏览器如何截图 谷歌浏览器页面截图技巧谷歌浏览器如何截图 谷歌浏览器页面截图技巧谷歌浏览器如何截图 谷歌浏览器页面截图技巧

    使用谷歌浏览器的开发者工具截图步骤:1. 按ctrl+shift+i(windows/linux)或cmd+option+i(mac)打开开发者工具。2. 点击右上角三个点,选择”更多工具”,再选择”截图”。3. 选择截取整个页面。推荐的谷歌浏览器扩展…

    2026年5月10日 用户投稿
    100
  • Python中怎样使用pymongo?

    在python中使用pymongo可以轻松地与mongodb数据库进行交互。1)安装pymongo:pip install pymongo。2)连接到mongodb:from pymongo import mongoclient; client = mongoclient(‘mongod…

    2026年5月10日
    000
  • JS如何实现迭代器?迭代器协议

    JavaScript中实现迭代器需遵循可迭代协议和迭代器协议,通过定义[Symbol.iterator]方法返回具备next()方法的迭代器对象,从而支持for…of和展开运算符;该机制统一了数据结构的遍历接口,实现惰性求值,适用于自定义对象、树、图及无限序列等复杂场景,提升代码通用性与…

    2026年5月10日
    000
  • JavaScript函数中插入加载动画(Spinner)的正确方法

    本文旨在解决在JavaScript函数中插入加载动画(Spinner)时遇到的异步问题。通过引入async/await和Promise.all,确保在数据处理完成前后正确显示和隐藏加载动画,提升用户体验。我们将提供两种实现方案,并详细解释其原理和优势。 在Web开发中,当执行耗时操作时,显示加载动画…

    2026年5月10日
    100

发表回复

登录后才能评论
关注微信