第35单元 数据的排序和描述
使用frame来表示数据是远远不够的。接下来我们需要一个对数据进行排序和描述的标尺。Python有通用的标尺函数len()以及该函数的“兄弟函数”min()和max(),这几个函数是不错的出发点。但是除了多少个、多少钱这样的问题外,我们经常需要知道更多问题的答案。pandas提供了许多函数,用于排序、分级、计数、会员测试和获取描述性的统计信息。
排序和分级
series和frame可以按索引或值进行排序。函数sort_index()返回按索引排序的frame(该函数不适用于series)。排序顺序总是字典序(数字按数值大小排序,字符串按字母表的顺序排序),可以使用参数ascending(默认值为True)来控制升序或降序。和之前一样,选项inplace=True可以使pandas对原始的frame进行排序。
population.sort_index().head() ➾ Population ➾ State ➾ Alabama 4708708 ➾ Alaska 698473 ➾ Arizona 6595778 ➾ Arkansas 2889450 ➾ California 36961664
函数sort_values()返回一个按值排序的frame或series。对于frame来说,第一个参数是某一列的名称或者一组列名称构成的列表,对应的可选参数ascending可以是布尔值或布尔值构成的列表(与要排序的数据列一一对应)。参数na_position(取值为"first"或"last")指定值为nan的单元在排序后的位置(在开头或结尾)。
population.sort_values("Population").head() ➾ Population ➾ State ➾ Wyoming 544270 ➾ District of Columbia 599657 ➾ Vermont 621760 ➾ North Dakota 646844 ➾ Alaska 698473
你知道怀俄明州(Wyoming)是美国人口最少的州吗?现在经过这一番数据分析后,这个事实就很清楚了。
函数rank()为frame或series的每个值计算一个数值等级。如果有相等的值,则该函数会给它们分配一个平均的等级。布尔型参数numeric_only仅将等级限制为数值。参数na_option(取值为"top"、"bottom"或"keep")设定nan的处理方式:将它们移动到新frame的顶部或底部,又或者将它们保留在原始的frame中。
pop_by_state = population.sort_index() pop_by_state.rank().head() ➾ Population ➾ State ➾ Alabama 29 ➾ Alaska 5 ➾ Arizona 38 ➾ Arkansas 20 ➾ California 51
现在你只需要敲十几个按键来将上面的输出与原始的人口frame相合并或连接,就可以得到一个包含实际人口以及州的排名的frame。
描述性统计量
描述性统计函数计算一个series或frame的每一列的和(sum())、均值(mean())、中值(median())、标准差(std())、数量(count())、最小值(min())和最大值(max())。这些函数都可以使用布尔型参数skipna,它控制是否从分析中排除nan值,而参数axis告诉函数以哪种方向获取数据(“垂直”或“水平”)。
alco2009.max() ➾ Beer 1.72 ➾ Wine 1.00 ➾ Spirits 1.82 ➾ dtype: float64 alco2009.min(axis=1) ➾ State ➾ Alabama 0.22 ➾ Alaska 0.54 ➾ Arizona 0.38 ➾ Arkansas 0.17 ➾ California 0.55 ➾ dtype: float64 alco2009.sum() ➾ Beer 63.22 ➾ Wine 19.59 ➾ Spirits 41.81 ➾ dtype: float64
函数argmax()(针对series)和idxmax()(针对frame)找出最大值首次出现的索引位置。这两个函数很容易记住:它们是pandas在处理series和frame时仅有的没有统一的两个函数。
pandas对伪积分、伪微分和其他累积方法的支持比较有限。函数cumsum()、cumprod()、cummin()和cummax()分别计算从series或frame的每列中的第一项开始的累积和、累积乘积、累积最小值和累积最大值。可以使用cumsum()函数获得夏威夷(或其他任意一个州)的累积酒精消费量:
alco.ix['Hawaii'].cumsum().head() ➾ Beer Wine Spirits Total ➾ Year ➾ 1977 1.61 0.36 1.26 3.23 ➾ 1978 2.99 0.82 2.56 6.37 ➾ 1979 4.59 1.26 3.84 9.69 ➾ 1980 6.24 1.72 5.05 13.01 ➾ 1981 7.98 2.16 6.21 16.35
函数diff()计算连续的列或series项之间的滑动差。计算结果的第一行是没有定义的。使用diff()函数也可以找出夏威夷每年酒消费量的变化情况:
alco.ix['Hawaii'].diff().head() ➾ Beer Wine Spirits Total ➾ Year ➾ 1977 NaN NaN NaN NaN ➾ 1978 -0.23 0.10 0.04 -9.000000e-02 ➾ 1979 0.22 -0.02 -0.02 1.800000e-01 ➾ 1980 0.05 0.02 -0.07 -4.440892e-16 ➾ 1981 0.09 -0.02 -0.05 2.000000e-02
执行伪微分操作之后,计算结果中最后一列的名称具有误导性。可以将其改为“Δ(Total)”“Change of Total”等,以免混淆。
唯一性、计数、会员资格
numpy可以将数组视为集合(如第28单元所述)。pandas也可以将series作为集合来处理(但frame是不能这样处理的)。下面我们再次使用第28单元中伪生物信息学的例子,来认真地练习我们的series集合技能:
dna = "AGTCCGCGAATACAGGCTCGGT" dna_as_series = pd.Series(list(dna), name="genes") dna_as_series.head() ➾ 0 A ➾ 1 G ➾ 2 T ➾ 3 C ➾ 4 C ➾ Name: genes, dtype: object
函数unique()和value_counts()分别算出series和frame中不同值组成的数组,并能给出每个不同值出现的次数(可以将其与第7单元的计数器Counter相比较)。如果series中包含nan,则它们同样会被计数。
dna_as_series.unique() ➾ array(['A', 'G', 'T', 'C'], dtype=object) dna_as_series.value_counts().sort_index() ➾ A 5 ➾ C 6 ➾ G 7 ➾ T 4 ➾ Name: genes, dtype: int64
isin()函数是专门为pandas的两个主要数据类型(即series和frame)定义的。它返回一个与数据大小相同的布尔型的series或frame,用于确定series或frame的每一项是否存在于某个集合中。我们知道,在DNA序列中只有核苷酸A、C、G和T。下面的代码可以告诉我们,之前构造出的DNA序列中所有的核苷酸是否都有效。
valid_nucs = list("ACGT") dna_as_series.isin(valid_nucs).all() ➾ True
至此,你应该对数据感到非常满意了,或许你已经等不及要进行一些数值处理,以期获得很棒的结果。接下来我们就来介绍数据转换的工具。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论