四、大数据深入浅出之python pandas(十四万字长文《下》) |
您所在的位置:网站首页 › dataframe组成部分 › 四、大数据深入浅出之python pandas(十四万字长文《下》) |
十五、pandas统计函数 Pandas 的本质是统计学原理在计算机领域的一种应用实现,通过编程的方式达到分析、描述数据的目的。而统计函数则是统计学中用于计算和分析数据的一种工具。在数据分析的过程中,使用统计函数有助于我们理解和分析数据。本节将学习几个常见的统计函数,比如百分比函数、协方差函数、相关系数等。 百分比变化(pct_change)Series 和 DatFrames 都可以使用 pct_change() 函数。该函数将每个元素与其前一个元素进行比较,并计算前后数值的百分比变化。示例如下: import pandas as pd import numpy as np #Series结构 s = pd.Series([1,2,3,4,5,4]) print (s.pct_change()) #DataFrame df = pd.DataFrame(np.random.randn(5, 2)) print(df.pct_change()) 输出结果: 10 NaN 21 1.000000 32 0.500000 43 0.333333 54 0.250000 65 -0.200000 7dtype: float64 8 0 1 90 NaN NaN 101 74.779242 0.624260 112 -0.353652 -1.104352 123 -2.422813 -13.994103 134 -3.828316 -1.853092 默认情况下,pct_change() 对列进行操作,如果想要操作行,则需要传递参数 axis=1 参数。示例如下: import pandas as pd import numpy as np #DataFrame df = pd.DataFrame(np.random.randn(3, 2)) print(df.pct_change(axis=1)) 输出结果: 1 0 1 20 NaN 3.035670 31 NaN -0.318259 42 NaN 0.227580 协方差(cov)Series 对象提供了一个cov方法用来计算 Series 对象之间的协方差。同时,该方法也会将缺失值(NAN )自动排除。 示例如下: import pandas as pd import numpy as np s1 = pd.Series(np.random.randn(10)) s2 = pd.Series(np.random.randn(10)) print (s1.cov(s2)) 输出结果: 10.20789380904226645 当应用于 DataFrame 时,协方差(cov)将计算所有列之间的协方差。 import pandas as pd import numpy as np frame = pd.DataFrame(np.random.randn(10, 5), columns=['a', 'b', 'c', 'd', 'e']) #计算a与b之间的协方差值 print (frame['a'].cov(frame['b'])) #计算所有数列的协方差值 print (frame.cov()) 输出结果: 1-0.37822395480394827 2 a b c d e 3a 1.643529 -0.378224 0.181642 0.049969 -0.113700 4b -0.378224 1.561760 -0.054868 0.144664 -0.231134 5c 0.181642 -0.054868 0.628367 -0.125703 0.324442 6d 0.049969 0.144664 -0.125703 0.480301 -0.388879 7e -0.113700 -0.231134 0.324442 -0.388879 0.848377 相关系数(corr)相关系数显示任意两个 Series 之间的线性关系。Pandas 提供了计算相关性的三种方法,分别是 pearson(default)、spearman() 和 kendall()。 import pandas as pd import numpy as np df = pd.DataFrame(np.random.randn(10, 5), columns=['a', 'b', 'c', 'd', 'e']) print (df['b'].corr(frame['c'])) print (df.corr()) 输出结果: 10.5540831507407936 2 a b c d e 3a 1.000000 -0.500903 -0.058497 -0.767226 0.218416 4b -0.500903 1.000000 -0.091239 0.805388 -0.020172 5c -0.058497 -0.091239 1.000000 0.115905 0.083969 6d -0.767226 0.805388 0.115905 1.000000 0.015028 7e 0.218416 -0.020172 0.083969 0.015028 1.000000 注意:如果 DataFrame 存在非数值(NAN),该方法会自动将其删除。 排名(rank)rank() 按照某种规则(升序或者降序)对序列中的元素值排名,该函数的返回值的也是一个序列,包含了原序列中每个元素值的名次。如果序列中包含两个相同的的元素值,那么会为其分配两者的平均排名。示例如下: import pandas as pd import numpy as np #返回5个随机值,然后使用rank对其排名 s = pd.Series(np.random.randn(5), index=list('abcde')) s['d'] = s['b'] print(s) #a/b排名分别为2和3,其平均排名为2.5 print(s.rank()) 输出结果: 1a -0.689585 2b -0.545871 3c 0.148264 4d -0.545871 5e -0.205043 6dtype: float64 7 8排名后输出: 9a 1.0 10b 2.5 11c 5.0 12d 2.5 13e 4.0 14dtype: float64 method参数rank() 提供了 method 参数,可以针对相同数据,进行不同方式的排名。如下所示: average:默认值,如果数据相同则分配平均排名;min:给相同数据分配最低排名;max:给相同数据分配最大排名;first:对于相同数据,根据出现在数组中的顺序进行排名。2) aisx&asceningrank() 有一个ascening参数, 默认为 True 代表升序;如果为 False,则表示降序排名(将较大的数值分配给较小的排名)。 rank() 默认按行方向排名(axis=0),也可以更改为 axis =1,按列排名。示例如下: import pandas as pd import numpy as np a = pd.DataFrame(np.arange(12).reshape(3,4),columns = list("abdc")) a =a.sort_index(axis=1,ascending=False) a.iloc[[1,1],[1,2]] = 6 #按行排名,将相同数值设置为所在行数值的最大排名 print(a.rank(axis=1,method="max")) 输出结果: 1 d c b a 20 3.0 4.0 2.0 1.0 31 4.0 4.0 4.0 1.0 42 3.0 4.0 2.0 1.0 与 method="min"进行对比,如下所示: import pandas as pd import numpy as np a = pd.DataFrame(np.arange(12).reshape(3,4),columns = list("abdc")) a =a.sort_index(axis=1,ascending=False) a.iloc[[1,1],[1,2]] = 6 #按行排名,将相同数值设置为所在行数值的最小排名 print(a.rank(axis=1,method="min")) 输出结果: 1 d c b a 20 3.0 4.0 2.0 1.0 31 2.0 2.0 2.0 1.0 42 3.0 4.0 2.0 1.0 十六、pandas窗口函数为了能更好地处理数值型数据,Pandas 提供了几种窗口函数,比如移动函数(rolling)、扩展函数(expanding)和指数加权函数(ewm)。 窗口函数应用场景非常多。举一个简单的例子:现在有 10 天的销售额,而您想每 3 天求一次销售总和,也就说第五天的销售额等于(第三天 + 第四天 + 第五天)的销售额之和,此时窗口函数就派上用场了。 窗口是一种形象化的叫法,这些函数在执行操作时,就如同窗口一样在数据区间上移动。 本节学习主要讲解如何在 DataFrame 和 Series 对象上应用窗口函数。 rolling()rolling() 又称移动窗口函数,它可以与 mean、count、sum、median、std 等聚合函数一起使用。为了使用方便,Pandas 为移动函数定义了专门的方法聚合方法,比如 rolling_mean()、rolling_count()、rolling_sum() 等。其的语法格式如下: 1rolling(window=n, min_periods=None, center=False) 常用参数说明如下: 参数名称说明window默认值为 1,表示窗口的大小,也就是观测值的数量,min_periods表示窗口的最小观察值,默认与 window 的参数值相等。center是否把中间值做为窗口标准,默认值为 False。下面看一组示例: import pandas as pd import numpy as np #生成时间序列 df = pd.DataFrame(np.random.randn(8, 4),index = pd.date_range('12/1/2020', periods=8),columns = ['A', 'B', 'C', 'D']) print(df) #每3个数求求一次均值 print(df.rolling(window=3).mean()) 输出结果: 1 A B C D 22020-12-01 0.580058 -0.715246 0.440427 -1.106783 32020-12-02 -1.313982 0.068954 -0.906665 1.382941 42020-12-03 0.349844 -0.549509 -0.806577 0.261794 52020-12-04 -0.497054 0.921995 0.232008 -0.815291 62020-12-05 2.658108 0.447783 0.049340 0.329209 72020-12-06 -0.271670 -0.070299 0.860684 -0.095122 82020-12-07 -0.706780 -0.949392 0.679680 0.230930 92020-12-08 0.027379 -0.056543 -1.067625 1.386399 10 11 A B C D 122020-12-01 NaN NaN NaN NaN 132020-12-02 NaN NaN NaN NaN 142020-12-03 -0.128027 -0.398600 -0.424272 0.179317 152020-12-04 -0.487064 0.147147 -0.493745 0.276481 162020-12-05 0.836966 0.273423 -0.175076 -0.074763 172020-12-06 0.629794 0.433160 0.380677 -0.193734 182020-12-07 0.559886 -0.190636 0.529901 0.155006 192020-12-08 -0.317024 -0.358745 0.157580 0.507402 window=3表示是每一列中依次紧邻的每 3 个数求一次均值。当不满足 3 个数时,所求值均为 NaN 值,因此前两列的值为 NaN,直到第三行值才满足要求 window =3。求均值的公式如下所示: (index1+index2+index3)/3 expanding()expanding() 又叫扩展窗口函数,扩展是指由序列的第一个元素开始,逐个向后计算元素的聚合值。 下面示例,min_periods = n表示向后移动 n 个值计求一次平均值: import pandas as pd import numpy as np df = pd.DataFrame(np.random.randn(10, 4), index = pd.date_range('1/1/2018', periods=10), columns = ['A', 'B', 'C', 'D']) print (df.expanding(min_periods=3).mean()) 输出结果: 1 A B C D 22020-01-01 NaN NaN NaN NaN 32020-01-02 NaN NaN NaN NaN 42020-01-03 -0.567833 0.258723 0.498782 0.403639 52020-01-04 -0.384198 -0.093490 0.456058 0.459122 62020-01-05 -0.193821 0.085318 0.389533 0.552429 72020-01-06 -0.113941 0.252397 0.214789 0.455281 82020-01-07 0.147863 0.400141 -0.062493 0.565990 92020-01-08 -0.036038 0.452132 -0.091939 0.371364 102020-01-09 -0.043203 0.368912 -0.033141 0.328143 112020-01-10 -0.100571 0.349378 -0.078225 0.225649 设置 min_periods=3,表示至少 3 个数求一次均值,计算方式为 (index0+index1+index2)/3,而 index3 的计算方式是 (index0+index1+index2+index3)/3,依次类推。 ewm()ewm(全称 Exponentially Weighted Moving)表示指数加权移动。ewn() 函数先会对序列元素做指数加权运算,其次计算加权后的均值。该函数通过指定 com、span 或者 halflife 参数来实现指数加权移动。示例如下: import pandas as pd import numpy as np df = pd.DataFrame(np.random.randn(10, 4), index = pd.date_range('12/1/2020', periods=10), columns = ['A', 'B', 'C', 'D']) #设置com=0.5,先加权再求均值 print(df.ewm(com=0.5).mean()) 输出结果: 1 A B C D 22020-12-01 -1.511428 1.427826 0.252652 0.093601 32020-12-02 -1.245101 -0.118346 0.170232 -0.207065 42020-12-03 0.131456 -0.271979 -0.679315 -0.589689 52020-12-04 -0.835228 0.094073 -0.973924 -0.081684 62020-12-05 1.279812 1.099368 0.203033 0.019014 72020-12-06 0.132027 -0.625744 -0.145090 -0.318155 82020-12-07 0.820230 0.371620 0.119683 -0.227101 92020-12-08 1.088283 -0.275570 0.358557 -1.050606 102020-12-09 0.538304 -1.288146 0.590358 -0.164057 112020-12-10 0.589177 -1.514472 -0.613158 0.367322 在数据分析的过程中,使用窗口函数能够提升数据的准确性,并且使数据曲线的变化趋势更加平滑,从而让数据分析变得更加准确、可靠 十七、应用聚合函数首先让我们创建一个 DataFrame 对象,然后对聚合函数进行应用。 import pandas as pd import numpy as np df = pd.DataFrame(np.random.randn(5, 4),index = pd.date_range('12/14/2020', periods=5),columns = ['A', 'B', 'C', 'D']) print (df) #窗口大小为3,min_periods 最小观测值为1 r = df.rolling(window=3,min_periods=1) print(r) 输出结果: 1 A B C D 22020-12-14 0.941621 1.205489 0.473771 -0.348169 32020-12-15 -0.276954 0.076387 0.104194 1.537357 42020-12-16 0.582515 0.481999 -0.652332 -1.893678 52020-12-17 -0.286432 0.923514 0.285255 -0.739378 62020-12-18 2.063422 -0.465873 -0.946809 1.590234 7 8Rolling [window=3,min_periods=1,center=False,axis=0] 对整体聚合您可以把一个聚合函数传递给 DataFrame,示例如下:import pandas as pdimport numpy as npdf = pd.DataFrame(np.random.randn(5, 4),index = pd.date_range('12/14/2020', periods=5),columns = ['A', 'B', 'C', 'D'])print (df)#窗口大小为3,min_periods 最小观测值为1r = df.rolling(window=3,min_periods=1)#使用 aggregate()聚合操作print(r.aggregate(np.sum))输出结果:1 A B C D22020-12-14 0.133713 0.746781 0.499385 0.58979932020-12-15 -0.777572 0.531269 0.600577 -0.39362342020-12-16 0.408115 -0.874079 0.584320 0.50758052020-12-17 -1.033055 -1.185399 -0.546567 2.09464362020-12-18 0.469394 -1.110549 -0.856245 0.26082778 A B C D92020-12-14 0.133713 0.746781 0.499385 0.589799102020-12-15 -0.643859 1.278050 1.099962 0.196176112020-12-16 -0.235744 0.403971 1.684281 0.703756122020-12-17 -1.402513 -1.528209 0.638330 2.208601132020-12-18 -0.155546 -3.170027 -0.818492 2.863051对任意某一列聚合import pandas as pdimport numpy as npdf = pd.DataFrame(np.random.randn(5, 4),index = pd.date_range('12/14/2020', periods=5),columns = ['A', 'B', 'C', 'D'])#窗口大小为3,min_periods 最小观测值为1r = df.rolling(window=3,min_periods=1)#对 A 列聚合print(r['A'].aggregate(np.sum))输出结果:12020-12-14 1.05150122020-12-15 1.35457432020-12-16 0.89633542020-12-17 0.50847052020-12-18 2.3337326Freq: D, Name: A, dtype: float64对多列数据聚合import pandas as pdimport numpy as npdf = pd.DataFrame(np.random.randn(5, 4),index = pd.date_range('12/14/2020', periods=5),columns = ['A', 'B', 'C', 'D'])#窗口大小为3,min_periods 最小观测值为1r = df.rolling(window=3,min_periods=1)#对 A/B 两列聚合print(r['A','B'].aggregate(np.sum))输出结果:1 A B22020-12-14 0.639867 -0.22999032020-12-15 0.352028 0.25791842020-12-16 0.637845 2.64362852020-12-17 0.432715 2.42860462020-12-18 -1.575766 0.969600对单列应用多个函数import pandas as pdimport numpy as npdf = pd.DataFrame(np.random.randn(5, 4),index = pd.date_range('12/14/2020', periods=5),columns = ['A', 'B', 'C', 'D'])#窗口大小为3,min_periods 最小观测值为1r = df.rolling(window=3,min_periods=1)#对 A/B 两列聚合print(r['A','B'].aggregate([np.sum,np.mean]))输出结果:1 sum mean22020-12-14 -0.469643 -0.46964332020-12-15 -0.626856 -0.31342842020-12-16 -1.820226 -0.60674252020-12-17 -2.007323 -0.66910862020-12-18 -0.595736 -0.198579对不同列应用多个函数import pandas as pdimport numpy as npdf = pd.DataFrame(np.random.randn(5, 4), index = pd.date_range('12/11/2020', periods=5), columns = ['A', 'B', 'C', 'D'])r = df.rolling(window=3,min_periods=1)print( r['A','B'].aggregate([np.sum,np.mean]))输出结果:1 A B2 sum mean sum mean32020-12-14 -1.428882 -1.428882 -0.417241 -0.41724142020-12-15 -1.315151 -0.657576 -1.580616 -0.79030852020-12-16 -2.093907 -0.697969 -2.260181 -0.75339462020-12-17 -1.324490 -0.441497 -1.578467 -0.52615672020-12-18 -2.400948 -0.800316 -0.452740 -0.150913对不同列应用不同函数import pandas as pd import numpy as np df = pd.DataFrame(np.random.randn(3, 4), index = pd.date_range('12/14/2020', periods=3), columns = ['A', 'B', 'C', 'D']) r = df.rolling(window=3,min_periods=1) print(r.aggregate({'A': np.sum,'B': np.mean})) 输出结果: 1 A B 22020-12-14 0.503535 -1.301423 32020-12-15 0.170056 -0.550289 42020-12-16 -0.086081 -0.140532 十八、pandas缺失值处理在一些数据分析业务中,数据缺失是我们经常遇见的问题,缺失值会导致数据质量的下降,从而影响模型预测的准确性,这对于机器学习和数据挖掘影响尤为严重。因此妥善的处理缺失值能够使模型预测更为准确和有效。 为什么会存在缺失值?前面章节的示例中,我们遇到过很多 NaN 值,关于缺失值您可能会有很多疑问,数据为什么会丢失数据呢,又是从什么时候丢失的呢?通过下面场景,您会得到答案。 其实在很多时候,人们往往不愿意过多透露自己的信息。假如您正在对用户的产品体验做调查,在这个过程中您会发现,一些用户很乐意分享自己使用产品的体验,但他是不愿意透露自己的姓名和联系方式;还有一些用户愿意分享他们使用产品的全部经过,包括自己的姓名和联系方式。因此,总有一些数据会因为某些不可抗力的因素丢失,这种情况在现实生活中会经常遇到。 什么是稀疏数据?稀疏数据,指的是在数据库或者数据集中存在大量缺失数据或者空值,我们把这样的数据集称为稀疏数据集。稀疏数据不是无效数据,只不过是信息不全而已,只要通过适当的方法就可以“变废为宝”。 稀疏数据的来源与产生原因有很多种,大致归为以下几种: 由于调查不当产生的稀疏数据;由于天然限制产生的稀疏数据;文本挖掘中产生的稀疏数据。缺失值处理那么 Pandas 是如何处理缺失值的呢,下面让我们一起看一下。 import pandas as pd import numpy as np df = pd.DataFrame(np.random.randn(5, 3), index=['a', 'c', 'e', 'f','h']) df = df.reindex(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']) print(df) 输出结果: 1 0 1 2 2a 0.187208 -0.951407 0.316340 3b NaN NaN NaN 4c -0.365741 -1.983977 -1.052170 5d NaN NaN NaN 6e -1.024180 1.550515 0.317156 7f -0.799921 -0.686590 1.383229 8g NaN NaN NaN 9h -0.207958 0.426733 -0.325951 上述示例,通过使用 reindex(重构索引),我们创建了一个存在缺少值的 DataFrame 对象。 检查缺失值为了使检测缺失值变得更容易,Pandas 提供了 isnull() 和 notnull() 两个函数,它们同时适用于 Series 和 DataFrame 对象。 import pandas as pd import numpy as np df = pd.DataFrame(np.random.randn(5, 3), index=['a', 'c', 'e', 'f','h']) df = df.reindex(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']) print(df['noe'].isnull()) 输出结果: 1a False 2b True 3c False 4d True 5e False 6f False 7g True 8h False 9Name: 1, dtype: bool notnull() 函数,使用示例: import pandas as pd import numpy as np df = pd.DataFrame(np.random.randn(5, 3), index=['a', 'c', 'e', 'f','h']) df = df.reindex(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']) print df['one'].notnull() 输出结果: 1a True 2b False 3c True 4d False 5e True 6f True 7g False 8h True 9Name: 1, dtype: bool 缺失数据计算计算缺失数据时,需要注意两点:首先数据求和时,将 NA 值视为 0 ,其次,如果要计算的数据为 NA,那么结果就是 NA。示例如下: import pandas as pd import numpy as np df = pd.DataFrame(np.random.randn(5, 3), index=['a', 'c', 'e', 'f','h'],columns=['one', 'two', 'three']) df = df.reindex(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']) print (df['one'].sum()) print() 输出结果: 13.4516595395128 清理并填充缺失值Pandas 提供了多种方法来清除缺失值。fillna() 函数可以实现用非空数据“填充”NaN 值。 用标量值替换NaN值下列程序将 NaN 值 替换为了 0,如下所示:import pandas as pdimport numpy as npdf = pd.DataFrame(np.random.randn(3, 3), index=['a', 'c', 'e'],columns=['one','two', 'three'])df = df.reindex(['a', 'b', 'c'])print(df)#用 0 填充 NaNprint (df.fillna(0))输出结果:1 one two three2a 1.497185 -0.703897 -0.0505133b NaN NaN NaN4c 2.008315 1.342690 -0.25585556 one two three7a 1.497185 -0.703897 -0.0505138b 0.000000 0.000000 0.0000009c 2.008315 1.342690 -0.255855当然根据您自己的需求,您也可以用其他值进行填充。向前和向后填充NAimport pandas as pdimport numpy as npdf = pd.DataFrame(np.random.randn(5, 3), index=['a', 'c', 'e', 'f','h'],columns=['one', 'two', 'three'])df = df.reindex(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])print df.fillna(method='ffill')输出结果:1 one two three2a 0.871741 0.311057 0.0910053b 0.871741 0.311057 0.0910054c 0.107345 -0.662864 0.8267165d 0.107345 -0.662864 0.8267166e 1.630221 0.482504 -0.7287677f 1.283206 -0.145178 0.1091558g 1.283206 -0.145178 0.1091559h 0.222176 0.886768 0.347820或者您也可以采用向后填充的方法。使用replace替换通用值在某些情况下,您需要使用 replace() 将 DataFrame 中的通用值替换成特定值,这和使用 fillna() 函数替换 NaN 值是类似的。示例如下: import pandas as pd import numpy as np df = pd.DataFrame({'one':[10,20,30,40,50,666], 'two':[99,0,30,40,50,60]}) #使用replace()方法 print (df.replace({99:10,666:60,0:20})) 删除缺失值如果想删除缺失值,那么使用 dropna() 函数与参数 axis 可以实现。在默认情况下,按照 axis=0 来按行处理,这意味着如果某一行中存在 NaN 值将会删除整行数据。示例如下: import pandas as pd import numpy as np df = pd.DataFrame(np.random.randn(5, 3), index=['a', 'c', 'e', 'f','h'],columns=['one', 'two', 'three']) df = df.reindex(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']) print(df) #删除缺失值 print (df.dropna()) 输出结果: 1 one two three 2a -2.025435 0.617616 0.862096 3b NaN NaN NaN 4c -1.710705 1.780539 -2.313227 5d NaN NaN NaN 6e -2.347188 -0.498857 -1.070605 7f -0.159588 1.205773 -0.046752 8g NaN NaN NaN 9h -0.549372 -1.740350 0.444356 10 11 one two three 12a -2.025435 0.617616 0.862096 13c -1.710705 1.780539 -2.313227 14e -2.347188 -0.498857 -1.070605 15f -0.159588 1.205773 -0.046752 16h -0.549372 -1.740350 0.444356 axis = 1 表示按列处理,处理结果是一个空的 DataFrame 对象。 十九、pandas分组操作在数据分析中,经常会遇到这样的情况:根据某一列(或多列)标签把数据划分为不同的组别,然后再对其进行数据分析。比如,某网站对注册用户的性别或者年龄等进行分组,从而研究出网站用户的画像(特点)。在 Pandas 中,要完成数据的分组操作,需要使用 groupby() 函数,它和 SQL 的GROUP BY操作非常相似。 在划分出来的组(group)上应用一些统计函数,从而达到数据分析的目的,比如对分组数据进行聚合、转换,或者过滤。这个过程主要包含以下三步: 拆分(Spliting):表示对数据进行分组;应用(Applying):对分组数据应用聚合函数,进行相应计算;合并(Combining):最后汇总计算结果。下面对 groupby() 函数的应用过程进行具体的讲解。 创建DataFrame对象首先我们创建一个 DataFrame 对象,下面数据描述了某班学生,计算机选修课的考试成绩: import pandas as pd import numpy as np data = {'Name': ['John', 'Helen', 'Sona', 'Ella'], 'score': [82, 98, 91, 87], 'option_course': ['C#','Python','Java','C']} df = pd.DataFrame(data) print(df) 输出结果: 1 Name score option_course 20 John 82 C# 31 Helen 98 Python 42 Sona 91 Java 53 Ella 87 C 创建groupby分组对象使用 groupby() 可以沿着任意轴分组。您可以把分组时指定的键(key)作为每组的组名,方法如下所示: df.groupby("key")df.groupby("key",axis=1)df.groupby(["key1","key2"])通过上述方法对 DataFrame 对象进行分组操作: import pandas as pd import numpy as np data = {'Name': ['John', 'Helen', 'Sona', 'Ella'], 'score': [82, 98, 91, 87], 'option_course': ['C#','Python','Java','C']} df = pd.DataFrame(data) print(df) #生成分组groupby对象 print(df.groupby('score')) 输出结果: 1 查看分组结果groups查看分组结果通过调用groups属性查看分组结果:import pandas as pdimport numpy as npdata = {'Name': ['John', 'Helen', 'Sona', 'Ella'], 'score': [82, 98, 91, 87], 'option_course': ['C#','Python','Java','C']}df = pd.DataFrame(data)#查看分组print(df.groupby('score').groups)输出结果:1{82: Int64Index([0], dtype='int64'),287: Int64Index([3], dtype='int64'),391: Int64Index([2], dtype='int64'),498: Int64Index([1], dtype='int64')}多个列标签分组当然也可以指定多个列标签进行分组,示例如下: import pandas as pd import numpy as np data = {'Name': ['John', 'Helen', 'Sona', 'Ella'], 'score': [82, 98, 91, 87], 'option_course': ['C#','Python','Java','C']} df = pd.DataFrame(data) #查看分组 print(df.groupby(['Name','score']).groups) 输出结果: 1{('Ella', 87): Int64Index([3], dtype='int64'), 2('Helen', 98): Int64Index([1], dtype='int64'), 3('John', 82): Int64Index([0], dtype='int64'), 4('Sona', 91): Int64Index([2], dtype='int64')} 通过 get_group() 方法可以选择组内的具体数据项: import pandas as pd import numpy as np data = {'Name': ['John', 'Helen', 'Sona', 'Ella'], 'score': [82, 98, 91, 87], 'option_course': ['C#','Python','Java','C']} df = pd.DataFrame(data) #根据score来分组 grouped=df.groupby('score') #根据对应组的数据值,选择一个组 print(grouped.get_group(91)) 输出结果: 1 Name score option_course 22 Sona 91 Java 遍历分组数据通过以下方法来遍历分组数据,示例如下: import pandas as pd import numpy as np data = {'Name': ['John', 'Helen', 'Sona', 'Ella'], 'score': [82, 98, 91, 87], 'option_course': ['C#','Python','Java','C']} df = pd.DataFrame(data) #查看分组 grouped=df.groupby('score') for label, option_course in grouped: #其中key代表分组后字典的键,也就是score print(label) #字典对应的值选修的科目 print(option_course) 输出结果: 182 2 Name score option_course 30 John 82 C# 487 5 Name score option_course 63 Ella 87 C 791 8 Name score option_course 92 Sona 91 Java 1098 11 Name score option_course 121 Helen 98 Python 如上所示, groupby 对象的组名称与 score 中的的元素值一一对应。 应用聚合函数当您在创建 groupby 对象时,通过 agg() 函数可以对分组对象应用多个聚合函数: import pandas as pd import numpy as np data = {'name': ['John', 'Helen', 'Sona', 'Ella'], 'score': [82, 98, 91, 87], 'option_course': ['C#','Python','Java','C']} df = pd.DataFrame(data) grouped=df.groupby('name') #应用一个聚合函数求均值 print(grouped['score']).agg(np.mean) 输出结果: 1name 2Ella 87 3Helen 98 4John 82 5Sona 91 6Name: score, dtype: int64 当然,您也可以一次性应有多个聚合函数,示例如下: import pandas as pd import numpy as np data = {'name': ['John', 'Helen', 'Sona', 'Ella'], 'score': [82, 98, 91, 87], 'option_course': ['C#','Python','Java','C']} df = pd.DataFrame(data) grouped=df.groupby('name') print(grouped['score'].agg([np.size,np.mean,np.std])) 输出结果: 1 size mean std 2name 3Ella 1 87 NaN 4Helen 1 98 NaN 5John 1 82 NaN 6Sona 1 91 NaN 组的转换操作在组的行或列上可以执行转换操作,最终会返回一个与组大小相同的索引对象。示例如下: import pandas as pd import numpy as np df = pd.DataFrame({'种类':['水果','水果','水果','蔬菜','蔬菜','肉类','肉类'], '产地':['朝鲜','中国','缅甸','中国','菲律宾','韩国','中国'], '水果':['橘子','苹果','哈密瓜','番茄','椰子','鱼肉','牛肉'], '数量':[3,5,5,3,2,15,9], '价格':[2,5,12,3,4,18,20]}) #分组求均值,水果、蔬菜、肉类 #对可执行计算的数值列求均值 print(df.groupby('种类').transform(np.mean)) #transform()直接应用demean,实现去均值操作 demean = lambda arr:arr-arr.mean() print(df.groupby('种类').transform(demean)) #自定义函数 # 返回分组的前n行数据 def get_rows(df,n): #从1到n行的所有列 return df.iloc[:n,:] #分组后的组名作为行索引 print(df.groupby('种类').apply(get_rows,n=1)) 输出结果: 1 数量 价格 20 4.333333 6.333333 31 4.333333 6.333333 42 4.333333 6.333333 53 2.500000 3.500000 64 2.500000 3.500000 75 12.000000 19.000000 86 12.000000 19.000000 9 10 数量 价格 110 -1.333333 -4.333333 121 0.666667 -1.333333 132 0.666667 5.666667 143 0.500000 -0.500000 154 -0.500000 0.500000 165 3.000000 -1.000000 176 -3.000000 1.000000 18 19 种类 产地 水果 数量 价格 20种类 21水果 0 水果 朝鲜 橘子 3 2 22肉类 5 肉类 韩国 鱼肉 15 18 23蔬菜 3 蔬菜 中国 番茄 3 3 组的数据过滤操作通过 filter() 函数可以实现数据的筛选,该函数根据定义的条件过滤数据并返回一个新的数据集。 下面,筛选出参加比赛超过两次的球队(包含两次): import pandas as pd import numpy as np data = {'Team': ['Riders', 'Riders', 'Devils', 'Devils', 'Kings', 'kings', 'Kings', 'Kings', 'Riders', 'Royals', 'Royals', 'Riders'], 'Rank': [1, 2, 2, 3, 3,4 ,1 ,1,2 , 4,1,2], 'Year': [2014,2015,2014,2015,2014,2015,2016,2017,2016,2014,2015,2017], 'Points':[874,789,863,663,741,802,756,788,694,701,812,698]} df = pd.DataFrame(data) #定义lambda函数来筛选数据 print (df.groupby('Team').filter(lambda x: len(x) >= 2)) 输出结果: 1 Team Rank Year Points 20 Riders 1 2014 874 31 Riders 2 2015 789 44 Kings 3 2014 741 56 Kings 1 2016 756 67 Kings 1 2017 788 78 Riders 2 2016 694 811 Riders 2 2017 698 二十、pandas merge 合并操作Pandas 提供的 merge() 函数能够进行高效的合并操作,这与 SQL 关系型数据库的 MERGE 用法非常相似。从字面意思上不难理解,merge 翻译为“合并”,指的是将两个 DataFrame 数据表按照指定的规则进行连接,最后拼接成一个新的 DataFrame 数据表。 merge() 函数的法格式如下: pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,left_index=False, right_index=False, sort=True,suffixes=('_x', '_y'), copy=True) 参数说明,如下表所示: 参数名称说明left/right两个不同的 DataFrame 对象。on指定用于连接的键(即列标签的名字),该键必须同时存在于左右两个 DataFrame 中,如果没有指定,并且其他参数也未指定, 那么将会以两个 DataFrame 的列名交集做为连接键。left_on指定左侧 DataFrame 中作连接键的列名。该参数在左、右列标签名不相同,但表达的含义相同时非常有用。right_on指定左侧 DataFrame 中作连接键的列名。left_index布尔参数,默认为 False。如果为 True 则使用左侧 DataFrame 的行索引作为连接键,若 DataFrame 具有多层 索引(MultiIndex),则层的数量必须与连接键的数量相等。right_index布尔参数,默认为 False。如果为 True 则使用左侧 DataFrame 的行索引作为连接键。how要执行的合并类型,从 {'left', 'right', 'outer', 'inner'} 中取值,默认为“inner”内连接。sort布尔值参数,默认为True,它会将合并后的数据进行排序;若设置为 False,则按照 how 给定的参数值进行排序。suffixes字符串组成的元组。当左右 DataFrame 存在相同列名时,通过该参数可以在相同的列名后附加后缀名,默认为('_x','_y')。copy默认为 True,表示对数据进行复制。注意:Pandas 库的 merge() 支持各种内外连接,与其相似的还有 join() 函数(默认为左连接)。 下面创建两个不同的 DataFrame,然后对它们进行合并操作: import pandas as pd left = pd.DataFrame({ 'id':[1,2,3,4], 'Name': ['Smith', 'Maiki', 'Hunter', 'Hilen'], 'subject_id':['sub1','sub2','sub4','sub6']}) right = pd.DataFrame({ 'id':[1,2,3,4], 'Name': ['William', 'Albert', 'Tony', 'Allen'], 'subject_id':['sub2','sub4','sub3','sub6']}) print (left) print (right) 输出如下: 1 id Name subject_id 20 1 Smith sub1 31 2 Maiki sub2 42 3 Hunter sub4 53 4 Hilen sub6 6 7 id Name subject_id 80 1 William sub2 91 2 Albert sub4 102 3 Tony sub3 113 4 Allen sub6 在单个键上进行合并操作通过 on 参数指定一个连接键,然后对上述 DataFrame 进行合并操作:import pandas as pd left = pd.DataFrame({ 'id':[1,2,3,4], 'Name': ['Smith', 'Maiki', 'Hunter', 'Hilen'], 'subject_id':['sub1','sub2','sub4','sub6']}) right = pd.DataFrame({ 'id':[1,2,3,4], 'Name': ['William', 'Albert', 'Tony', 'Allen'], 'subject_id':['sub2','sub4','sub3','sub6']})#通过on参数指定合并的键print(pd.merge(left,right,on='id'))输出结果:1 id Name_x subject_id_x Name_y subject_id_y20 1 Smith sub1 William sub231 2 Maiki sub2 Albert sub442 3 Hunter sub4 Tony sub353 4 Hilen sub6 Allen sub6在多个键上进行合并操作下面示例,指定多个键来合并上述两个 DataFrame 对象: import pandas as pd left = pd.DataFrame({ 'id':[1,2,3,4], 'Name': ['Smith', 'Maiki', 'Hunter', 'Hilen'], 'subject_id':['sub1','sub2','sub4','sub6']}) right = pd.DataFrame({ 'id':[1,2,3,4], 'Name': ['Bill', 'Lucy', 'Jack', 'Mike'], 'subject_id':['sub2','sub4','sub3','sub6']}) print(pd.merge(left,right,on=['id','subject_id'])) 输出结果: 1 id Name_x subject_id Name_y 20 4 Hilen sub6 Mike 使用how参数合并通过how参数可以确定 DataFrame 中要包含哪些键,如果在左表、右表都不存的键,那么合并后该键对应的值为 NaN。为了便于大家学习,我们将 how 参数和与其等价的 SQL 语句做了总结: Merge方法等效 SQL描述leftLEFT OUTER JOIN使用左侧对象的keyrightRIGHT OUTER JOIN使用右侧对象的keyouterFULL OUTER JOIN使用左右两侧所有key的并集innerINNER JOIN使用左右两侧key的交集left joinimport pandas as pd left = pd.DataFrame({ 'id':[1,2,3,4], 'Name': ['Smith', 'Maiki', 'Hunter', 'Hilen'], 'subject_id':['sub1','sub2','sub4','sub6']}) right = pd.DataFrame({ 'id':[1,2,3,4], 'Name': ['Bill', 'Lucy', 'Jack', 'Mike'], 'subject_id':['sub2','sub4','sub3','sub6']}) #以left侧的subject_id为键print(pd.merge(left,right,on='subject_id',how="left"))输出结果:1 id_x Name_x subject_id id_y Name_y20 1 Smith sub1 NaN NaN31 2 Maiki sub2 1.0 Bill42 3 Hunter sub4 2.0 Lucy53 4 Hilen sub6 4.0 Mikeright joinimport pandas as pd left = pd.DataFrame({ 'id':[1,2,3,4], 'Name': ['Smith', 'Maiki', 'Hunter', 'Hilen'], 'subject_id':['sub1','sub2','sub4','sub6']}) right = pd.DataFrame({ 'id':[1,2,3,4], 'Name': ['Bill', 'Lucy', 'Jack', 'Mike'], 'subject_id':['sub2','sub4','sub3','sub6']}) #以right侧的subject_id为键print(pd.merge(left,right,on='subject_id',how="right"))输出结果:1 id_x Name_x subject_id id_y Name_y20 2.0 Maiki sub2 1 Bill31 3.0 Hunter sub4 2 Lucy42 4.0 Hilen sub6 4 Mike53 NaN NaN sub3 3 Jackouter join(并集)import pandas as pd left = pd.DataFrame({ 'id':[1,2,3,4], 'Name': ['Smith', 'Maiki', 'Hunter', 'Hilen'], 'subject_id':['sub1','sub2','sub4','sub6']}) right = pd.DataFrame({ 'id':[1,2,3,4], 'Name': ['Bill', 'Lucy', 'Jack', 'Mike'], 'subject_id':['sub2','sub4','sub3','sub6']}) #求出两个subject_id的并集,并作为键print(pd.merge(left,right,on='subject_id',how="outer"))输出结果:1 id_x Name_x subject_id id_y Name_y20 1.0 Smith sub1 NaN NaN31 2.0 Maiki sub2 1.0 Bill42 3.0 Hunter sub4 2.0 Lucy53 4.0 Hilen sub6 4.0 Mike64 NaN NaN sub3 3.0 Jackinner join(交集)import pandas as pd left = pd.DataFrame({ 'id':[1,2,3,4], 'Name': ['Smith', 'Maiki', 'Hunter', 'Hilen'], 'subject_id':['sub1','sub2','sub4','sub6']}) right = pd.DataFrame({ 'id':[1,2,3,4], 'Name': ['Bill', 'Lucy', 'Jack', 'Mike'], 'subject_id':['sub2','sub4','sub3','sub6']}) #求出两个subject_id的交集,并将结果作为键 print(pd.merge(left,right,on='subject_id',how="inner")) 输出结果: 1 id_x Name_x subject_id id_y Name_y 20 2 Maiki sub2 1 Bill 31 3 Hunter sub4 2 Lucy 42 4 Hilen sub6 4 Mike 注意:当 a 与 b 进行内连操作时 a.join(b) 不等于 b.join(a)。 二十一、pandas concat链接操作Pandas 通过 concat() 函数能够轻松地将 Series 与 DataFrame 对象组合在一起,函数的语法格式如下: 1pd.concat(objs,axis=0,join='outer',join_axes=None,ignore_index=False) 参数说明如下所示: 参数名称说明objs一个序列或者是Series、DataFrame对象。axis表示在哪个轴方向上(行或者列)进行连接操作,默认 axis=0 表示行方向。join指定连接方式,取值为{"inner","outer"},默认为 outer 表示取并集,inner代表取交集。ignore_index布尔值参数,默认为 False,如果为 True,表示不在连接的轴上使用索引。join_axes表示索引对象的列表。concat()concat() 函数用于沿某个特定的轴执行连接操作。下面让我们创建不同的对象,并对其进行连接。 import pandas as pd a= pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3'], 'C': ['C0', 'C1', 'C2', 'C3'], 'D': ['D0', 'D1', 'D2', 'D3']}, index=[0, 1, 2, 3]) b= pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'], 'B': ['B4', 'B5', 'B6', 'B7'], 'C': ['C4', 'C5', 'C6', 'C7'], 'D': ['D4', 'D5', 'D6', 'D7']}, #连接a与b print(pd.concat([a,b])) 输出结果: 1 A B C D 20 A0 B0 C0 D0 31 A1 B1 C1 D1 42 A2 B2 C2 D2 53 A3 B3 C3 D3 64 A4 B4 C4 D4 75 A5 B5 C5 D5 86 A6 B6 C6 D6 97 A7 B7 C7 D7 如果想把指定的键与 DataFrame 对象连接,您可以使用 keys 参数来实现。如下所示: import pandas as pd a= pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3'], 'C': ['C0', 'C1', 'C2', 'C3'], 'D': ['D0', 'D1', 'D2', 'D3']}, index=[0, 1, 2, 3]) b= pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'], 'B': ['B4', 'B5', 'B6', 'B7'], 'C': ['C4', 'C5', 'C6', 'C7'], 'D': ['D1', 'D2', 'D5', 'D6']}, index=[2,3,4,5]) #连接a与b,并给a,b连接一个指定的键 print(pd.concat([a,b],keys=['x','y'])) 输出结果: 1 A B C D 2x 0 A0 B0 C0 D0 3 1 A1 B1 C1 D1 4 2 A2 B2 C2 D2 5 3 A3 B3 C3 D3 6y 2 A4 B4 C4 D1 7 3 A5 B5 C5 D2 8 4 A6 B6 C6 D5 9 5 A7 B7 C7 D6 上述示中,可以看出行索引 index 存在重复使用的现象,如果想让输出的行索引遵循依次递增的规则,那么需要将 ignore_index 设置为 True。 import pandas as pd a= pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3'], 'C': ['C0', 'C1', 'C2', 'C3'], 'D': ['D0', 'D1', 'D2', 'D3']}, index=[0, 1, 2, 3]) b= pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'], 'B': ['B4', 'B5', 'B6', 'B7'], 'C': ['C4', 'C5', 'C6', 'C7'], 'D': ['D1', 'D2', 'D5', 'D6']}, index=[2,3,4,5]) #连接a与b,设置 ignore_index 等于 True print(pd.concat([a,b],keys=['x','y'],ignore_index=True)) 输出结果: 1 A B C D 20 A0 B0 C0 D0 31 A1 B1 C1 D1 42 A2 B2 C2 D2 53 A3 B3 C3 D3 64 A4 B4 C4 D1 75 A5 B5 C5 D2 86 A6 B6 C6 D5 97 A7 B7 C7 D6 注意:此时的索引顺序被改变了,而且键 keys 指定的键也被覆盖了。 如果您想要沿着 axis=1 添加两个对象,那么将会追加新的列。 import pandas as pd a= pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3'], 'C': ['C0', 'C1', 'C2', 'C3'], 'D': ['D0', 'D1', 'D2', 'D3']}, index=[0, 1, 2, 3]) b= pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'], 'B': ['B4', 'B5', 'B6', 'B7'], 'C': ['C4', 'C5', 'C6', 'C7'], 'D': ['D1', 'D2', 'D5', 'D6']}, index=[4,5,6,7]) #沿着 axis=1,连接a与b print(pd.concat([a,b],axis=1)) 输出结果: 1 A B C D A B C D 20 A0 B0 C0 D0 NaN NaN NaN NaN 31 A1 B1 C1 D1 NaN NaN NaN NaN 42 A2 B2 C2 D2 NaN NaN NaN NaN 53 A3 B3 C3 D3 NaN NaN NaN NaN 64 NaN NaN NaN NaN A4 B4 C4 D1 75 NaN NaN NaN NaN A5 B5 C5 D2 86 NaN NaN NaN NaN A6 B6 C6 D5 97 NaN NaN NaN NaN A7 B7 C7 D6 append()如果要连接 Series 和 DataFrame 对象,有一个最方便、快捷的方法,那就是 append() 方法。该方法沿着 axis=0 (行方向)进行操作。 import pandas as pd a= pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3'], 'C': ['C0', 'C1', 'C2', 'C3'], 'D': ['D0', 'D1', 'D2', 'D3']}, index=[0, 1, 2, 3]) b= pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'], 'B': ['B4', 'B5', 'B6', 'B7'], 'C': ['C4', 'C5', 'C6', 'C7'], 'D': ['D1', 'D2', 'D5', 'D6']}, index=[4,5,6,7]) #沿着 axis=0,使用 apppend()方法连接a与b print(a.append(b)) 输出结果: 1 A B C D 20 A0 B0 C0 D0 31 A1 B1 C1 D1 42 A2 B2 C2 D2 53 A3 B3 C3 D3 64 A4 B4 C4 D1 75 A5 B5 C5 D2 86 A6 B6 C6 D5 97 A7 B7 C7 D6 当然 append() 函数也可接收多个对象,示例如下: a= pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3'], 'C': ['C0', 'C1', 'C2', 'C3'], 'D': ['D0', 'D1', 'D2', 'D3']}, index=[0, 1, 2, 3]) b= pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'], 'B': ['B4', 'B5', 'B6', 'B7'], 'C': ['C4', 'C5', 'C6', 'C7'], 'D': ['D1', 'D2', 'D5', 'D6']}, index=[4,5,6,7]) c= pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'], 'B': ['B8', 'B9', 'B10', 'B7'], 'C': ['C9', 'C8', 'C7', 'C6'], 'D': ['D8', 'D5', 'D7', 'D6']}, index=[8,9,10,11]) print(a.append(b,c,a)) 输出结果: 1 A B C D 20 A0 B0 C0 D0 31 A1 B1 C1 D1 42 A2 B2 C2 D2 53 A3 B3 C3 D3 64 A4 B4 C4 D1 75 A5 B5 C5 D2 86 A6 B6 C6 D5 97 A7 B7 C7 D6 108 A4 B8 C9 D8 119 A5 B9 C8 D5 1210 A6 B10 C7 D7 1311 A7 B7 C6 D6 140 A0 B0 C0 D0 151 A1 B1 C1 D1 162 A2 B2 C2 D2 173 A3 B3 C3 D3 二十二、pandas时间序列顾名思义,时间序列(time series),就是由时间构成的序列,它指的是在一定时间内按照时间顺序测量的某个变量的取值序列,比如一天内的温度会随时间而发生变化,或者股票的价格会随着时间不断的波动,这里用到的一系列时间,就可以看做时间序列。时间序列包含三种应用场景,分别是: 特定的时刻(timestamp),也就是时间戳;固定的日期(period),比如某年某月某日;时间间隔(interval),每隔一段时间具有规律性;在处理时间序列的过程中,我们一般会遇到两个问题,第一,如何创建时间序列;第二,如何更改已生成时间序列的频率。 Pandas 为解决上述问题提供了一套简单、易用的方法。 下面用 Python 内置的 datetime 模块来获取当前时间,通过该模块提供的now()方法即可实现。 from datetime import datetime #数据类型为datetime print(datetime.now()) 输出结果: 12020-12-16 16:36:18.791297 创建时间戳TimeStamp(时间戳) 是时间序列中的最基本的数据类型,它将数值与时间点完美结合在一起。Pandas 使用下列方法创建时间戳: import pandas as pd print (pd.Timestamp('2017-03-01')) 输出结果: 2017-03-01 00:00:00 同样,可以将整型或浮点型表示的时间转换为时间戳。默认的单位是纳秒(时间戳单位),示例如下: import pandas as pd print(pd.Timestamp(1587687255,unit='s')) 输出结果: 12022-03-19 14:26:39 创建时间范围通过 date_range() 方法可以创建某段连续的时间或者固定间隔的时间时间段。该函数提供了三个参数,分别是: start:开始时间end:结束时间freq:时间频率,默认为 "D"(天)示例如下: import pandas as pd #freq表示时间频率,每30min变化一次 print(pd.date_range("9:00", "18:10", freq="30min").time) 输出结果: 1[datetime.time(9, 0) datetime.time(9, 30) datetime.time(10, 0) 2datetime.time(10, 30) datetime.time(11, 0) datetime.time(11, 30) 3datetime.time(12, 0) datetime.time(12, 30) datetime.time(13, 0) 4datetime.time(13, 30) datetime.time(14, 0) datetime.time(14, 30) 5datetime.time(15, 0) datetime.time(15, 30) datetime.time(16, 0) 6datetime.time(16, 30) datetime.time(17, 0) datetime.time(17, 30) 7datetime.time(18, 0)] 更改时间频率import pandas as pd #修改为按小时 print(pd.date_range("6:10", "11:45", freq="H").time) 输出结果: 1[datetime.time(6, 10) datetime.time(7, 10) datetime.time(8, 10) 2datetime.time(9, 10) datetime.time(10, 10) datetime.time(11, 10)] 转化为时间戳您可以使用 to_datetime() 函数将 series 或 list 转换为日期对象,其中 list 会转换为DatetimeIndex。示例如下: import pandas as pd print(pd.to_datetime(pd.Series(['Jun 3, 2020','2020-12-10', None]))) 输出结果: 10 22020-06-031 32020-12-10 42 NaT 5dtype: datetime64[ns] 注意:NaT 表示的不是时间 ,它等效于 NaN。 最后再来看一个示例: import pandas as pd #传入list,生成Datetimeindex print(pd.to_datetime(['Jun 31, 2020','2020-12-10', None])) 输出结果: 1DatetimeIndex(['2020-06-03', '2020-12-10', 'NaT'], dtype='datetime64[ns]', freq=None) 频率和周期转换Time Periods 表示时间跨度,一段时间周期,它被定义在 Pandas Periods 类中,通过该类提供的方法可以实现将频率转换为周期。比如 Periods() 方法,可以将频率 "M"(月)转换为 Period(时间段)。 下面示例,使用 asfreq() 和 start 参数,打印 "01" ,若使用 end 参数,则打印 "31"。示例如下: import pandas as pd x = pd.Period('2014', freq='M') #start参数 x.asfreq('D', 'start') #end参数 x.asfreq('D', 'end') 输出结果: 1Period('2014-01-01', 'D') 2Period('2014-01-31', 'D') 对于常用的时间序列频率,Pandas 为其规定了一些字符串别名,我们将这些别名称为“offset(偏移量)”。如下表所示: 别名描述别名描述B工作日频率BQS工作季度开始频率D日历日频率A年终频率W每周频率BA工作年度结束频率M月末频率BAS工作年度开始频率SM半月结束频率BH营业时间频率BM工作月结束频率H小时频率MS月开始频率T,min每分钟频率SMS半月开始频率S每秒钟频率BMS工作月开始频率L,ms毫秒Q季末频率U,us微妙BQ工作季度结束频率N纳秒QS季度开始频率时间周期计算周期计算,指的是对时间周期进行算术运算,所有的操作将在“频率”的基础上执行。 import pandas as pd #S表示秒 x = pd.Period('2014', freq='S') x 输出结果: 1Period('2014-01-01 00:00:00', 'S') 执行计算示例: import pandas as pd x = pd.Period('2014', freq='S') #加1s的时间 print(x+1) 输出结果: 1Period('2014-01-01 00:00:01', 'S') 再看一组完整的示例: #定义时期period,默认freq="Y"年份 p1=pd.Period('2020') p2=pd.Period('2019') #使用f''格式化输出 print(f'p1={p1}年') print(f'p2={p2}年') print(f'p1和p2间隔{p1-p2}年') #f''表示字符串格式化输出 print(f'五年前是{p1-5}年') 输出结果: 1p1=2020年 2p2=2019年 3p1和p2间隔年 4五年前是2015年 创建时间周期我们可以使用 period_range() 方法来创建时间周期范围。示例如下: import pandas as pd #Y表示年 p = pd.period_range('2016','2018', freq='Y') p 输出结果: 1PeriodIndex(['2016', '2017', '2018'], dtype='period[A-DEC]', freq='A-DEC') 时间序列转换如果想要把字符串日期转换为 Period,首先需要将字符串转换为日期格式,然后再将日期转换为 Period。示例如下: # 创建时间序列 index=pd.date_range("2020-03-17","2020-03-30",freq="1.5H") #随机选取4个互不相同的数 loc=np.random.choice(np.arange(len(index)),size=4,replace=False) loc.sort() ts_index=index[loc] ts_index pd_index=ts_index.to_periods('D') pd_index() 输出结果: 1DatetimeIndex(['2020-03-17 12:00:00', '2020-03-22 04:30:00', 2 '2020-03-27 03:00:00', '2020-03-30 00:00:00'], 3 dtype='datetime64[ns]', freq=None) 4 5PeriodIndex(['2020-03-17', '2020-03-19', '2020-03-19', '2020-03-27'], dtype='period[D]', freq='D') 使用 to_timestamp() 能够将 Period 时期转换为时间戳(timestamp),示例如下: import pandas as pd p1=pd.Periods("2020-2-3") p1.to_timestamp() 输出结果: 1Timestamp('2020-02-03 00:00:00') 创建日期范围Pandas 提供了用来创建日期序列的函数 date_range(),该函数的默认频率为 "D", 也就是“天”。日期序列只包含年、月、日,不包含时、分、秒。 下面是一组简单的示例,如下所示: import pandas as pd print(pd.date_range('12/15/2020', periods=10)) 输出结果: DatetimeIndex(['2020-12-15', '2020-12-16', '2020-12-17', '2020-12-18', '2020-12-19', '2020-12-20', '2020-12-21', '2020-12-22', '2020-12-23', '2020-12-24'], dtype='datetime64[ns]', freq='D') 当我们使用 date_range() 来创建日期范围时,该函数包含结束的日期,用数学术语来说就是区间左闭右闭,即包含起始值,也包含结束值。示例如下: import pandas as pd #建议使用Python的datetime模块创建时间 start = pd.datetime(2019, 1, 1) end = pd.datetime(2019, 1, 5) print pd.date_range(start,end) 输出结果: 1DatetimeIndex(['2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04','2019-01-05'] 2,dtype='datetime64[ns]', freq='D') 更改日频率使用下列方法可以修改频率,比如按“天”为按“月”,示例如下: import pandas as pd print(pd.date_range('12/15/2011', periods=5,freq='M')) 输出结果: 1DatetimeIndex(['2020-12-31', '2021-01-31', '2021-02-28', '2021-03-31', 2 '2021-04-30'],dtype='datetime64[ns]', freq='M') 工作日时间bdate_range() 表示创建工作日的日期范围,它与 date_range() 不同,它不包括周六、周日。 import pandas as pd print(pd.date_range('11/25/2020', periods=8)) 输出结果: 1DatetimeIndex(['2020-11-25', '2020-11-26', '2020-11-27', '2020-11-28','2020-11-29', '2020-11-30', '2020-12-01', '2020-12-02'],dtype='datetime64[ns]', freq='D') 上述方法中,date_range() 默认频率是日历日,而 bdate_range() 的默认频率是工作日。 二十三、pandas 日期时间格式化当进行数据分析时,我们会遇到很多带有日期、时间格式的数据集,在处理这些数据集时,可能会遇到日期格式不统一的问题,此时就需要对日期时间做统一的格式化处理。比如“Wednesday, June 6, 2020”可以写成“6/6/20”,或者写成“06-06-2020。 日期格式化符号在对时间进行格式化处理时,它们都有固定的表示格式,比如小时的格式化符号为%H ,分钟简写为%M ,秒简写为%S。下表对常用的日期格式化符号做了总结: 日期格式化符号符号说明%y两位数的年份表示(00-99)%Y四位数的年份表示(000-9999)%m月份(01-12)%d月内中的一天(0-31)%H24小时制小时数(0-23)%I12小时制小时数(01-12)%M分钟数(00=59)%S秒(00-59)%a本地英文缩写星期名称%A本地英文完整星期名称%b本地缩写英文的月份名称%B本地完整英文的月份名称%w星期(0-6),星期天为星期的开始%W一年中的星期数(00-53)星期一为星期的开始%x本地相应的日期表示%X本地相应的时间表示%Z当前时区的名称%U一年中的星期数(00-53)星期天为星期的开始%j年内的一天(001-366)%c本地相应的日期表示和时间表示Python处理Python 内置的 strptime() 方法能够将字符串日期转换为 datetime 类型,下面看一组示例: from datetime import datetime #将日期定义为字符串 date_str1 = 'Wednesday, July 18, 2020' date_str2 = '18/7/20' date_str3 = '18-07-2020' #将日期转化为datetime对象 dmy_dt1 = datetime.strptime(date_str1, '%A,%B%d,%Y') dmy_dt2 = datetime.strptime(date_str2, '%d/%m/%y') dmy_dt3 = datetime.strptime(date_str3, '%d-%m-%Y') #处理为相同格式,并打印输出 print(dmy_dt1) print(dmy_dt2) print(dmy_dt3) 输出结果: 12020-07-18 00:00:00 22020-07-18 00:00:00 32020-07-18 00:00:00 注意:strftime() 可以将 datetime 类型转换为字符串类型,恰好与 strptime() 相反。 Pandas处理除了使用 Python 内置的 strptime() 方法外,你还可以使用 Pandas 模块的 pd.to_datetime() 和 pd.DatetimeIndex() 进行转换。 to_datetime()通过 to_datetime() 直接转换为 datetime 类型import pandas as pdimport numpy as npdate = ['2012-05-06 11:00:00','2012-05-16 11:00:00']pd_date=pd.to_datetime(date)df=pd.Series(np.random.randn(2),index=pd_date)DatetimeIndex()使用 Datetimeindex() 函数设置时间序,示例如下: date = pd.DatetimeIndex(['1/1/2008', '1/2/2008', '1/3/2008', '1/4/2008', '1/5/2008']) dt = pd.Series(np.random.randn(5),index = date) print(dt) 输出结果: 12008-01-01 1.965619 22008-01-02 -2.897374 32008-01-03 0.625929 42008-01-04 1.204926 52008-01-05 1.755680 6dtype: float64 二十四、pandas Timedelta时间差Timedelta 表示时间差(或者时间增量),我们可以使用不同的时间单位来表示它,比如,天、小时、分、秒。时间差的最终的结果可以是正时间差,也可以是负时间差。 本节主要介绍创建 Timedelta (时间差)的方法以及与时间差相关的运算法则。 字符串通过传递字符串可以创建 Timedelta 对象,示例如下: import pandas as pd print(pd.Timedelta('5 days 8 hours 6 minutes 59 seconds')) 输出结果: 15 days 08:06:59 整数通过传递整数值和unit参数也可以创建一个 Timedelta 对象。 import pandas as pd print(pd.Timedelta(19,unit='h')) 输出结果: 10 days 19:00:00 数据偏移量数据偏移量, 比如,周(weeks)、天(days)、小时(hours)、分钟(minutes)、秒(milliseconds)、毫秒、微秒、纳秒都可以使用。 import pandas as pd print (pd.Timedelta(days=2,hours=6)) 输出结果: 12 days 06:00:00 to_timedelta()您可以使用pd.to_timedelta()方法,将具有 timedelta 格式的值 (标量、数组、列表或 Series)转换为 Timedelta 类型。如果输入是 Series,则返回 Series;如果输入是标量,则返回值也为标量,其他情况输出 TimedeltaIndex。示例如下: import pandas as pd print(pd.to_timedelta(['1 days 06:05:01.00003', '15.5us', 'nan'])) print(pd.to_timedelta(np.arange(5), unit='s')) 输出结果: 1TimedeltaIndex(['1 days 06:05:01.000030', '0 days 00:00:00.000015', NaT],dtype='timedelta64[ns]', freq=None) 2 3TimedeltaIndex(['0 days 00:00:00', '0 days 00:00:01', '0 days 00:00:02','0 days 00:00:03', 4'0 days 00:00:04'],dtype='timedelta64[ns]', freq=None) 算术操作通过对datetime64[ns]类型的时间序列或时间戳做算术运算,其运算结果依然是datetime64[ns]数据类型。接下来,我们创建一个带有 Timedelta 与 datetime 的 DataFrame 对象,并对其做一些算术运算。 import pandas as pd s = pd.Series(pd.date_range('2020-1-1', periods=5, freq='D')) #推导式用法 td = pd.Series([ pd.Timedelta(days=i) for i in range(5)]) df = pd.DataFrame(dict(A = s, B = td)) print(df) 输出结果: 1 A B 20 2020-01-01 0 days 31 2020-01-02 1 days 42 2020-01-03 2 days 53 2020-01-04 3 days 64 2020-01-05 4 days 加法运算import pandas as pd s = pd.Series(pd.date_range('20120-1-1', periods=3, freq='D')) td = pd.Series([ pd.Timedelta(days=i) for i in range(3) ]) df = pd.DataFrame(dict(A = s, B = td)) #加法运算 df['C']=df['A']+df['B'] print(df) 输出结果: 1 A B C 20 2020-01-01 0 days 2020-01-01 31 2020-01-02 1 days 2020-01-03 42 2020-01-03 2 days 2020-01-05 减法运算import pandas as pd s = pd.Series(pd.date_range('2012-1-1', periods=3, freq='D')) td = pd.Series([ pd.Timedelta(days=i) for i in range(3) ]) df = pd.DataFrame(dict(A = s, B = td)) df['C']=df['A']+df['B'] df['D']=df['C']-df['B'] print(df) 输出结果: 1 A B C D 20 2019-01-01 0 days 2019-01-01 2019-01-01 31 2019-01-02 1 days 2019-01-03 2019-01-02 42 2019-01-03 2 days 2019-01-05 2019-01-03 二十五、pandas sample 随机抽样随机抽样,是统计学中常用的一种方法,它可以帮助我们从大量的数据中快速地构建出一组数据分析模型。在 Pandas 中,如果想要对数据集进行随机抽样,需要使用 sample() 函数。 sample() 函数的语法格式如下: 1DataFrame.sample(n=None, frac=None, replace=False, weights=None, random_state=None, axis=None) 参数说明如下表所示: 参数名称参数说明n表示要抽取的行数。frac表示抽取的比例,比如 frac=0.5,代表抽取总体数据的50%。replace布尔值参数,表示是否以有放回抽样的方式进行选择,默认为 False,取出数据后不再放回。weights可选参数,代表每个样本的权重值,参数值是字符串或者数组。random_state可选参数,控制随机状态,默认为 None,表示随机数据不会重复;若为 1 表示会取得重复数据。axis表示在哪个方向上抽取数据(axis=1 表示列/axis=0 表示行)。该函数返回与数据集类型相同的新对象,相当于 numpy.random.choice()。实例如下: import pandas as pd dict = {'name':["Jack", "Tom", "Helen", "John"],'age': [28, 39, 34, 36],'score':[98,92,91,89]} info = pd.DataFrame(dict) #默认随机选择两行 info.sample(n=2) #随机选择两列 info.sample(n=2,axis=1) 输出结果: 1 name age score 23 John 36 89 30 Jack 28 98 4 5 score name 60 98 Jack 71 92 Tom 82 91 Helen 93 89 John 再来看一组示例: import pandas as pd info = pd.DataFrame({'data1': [2, 6, 8, 0], 'data2': [2, 5, 0, 8], 'data3': [12, 2, 1, 8]}, index=['John', 'Parker', 'Smith', 'William']) info #随机抽取3个数据 info['data1'].sample(n=3) #总体的50% info.sample(frac=0.5, replace=True) #data3序列为权重值,并且允许重复数据出现 info.sample(n=2, weights='data3', random_state=1) 输出结果: 1随机选择3行数据: 2William 0 3Smith 8 4Parker 6 5Name: data1, dtype: int64 6 7 data1 data2 data3 8John 2 2 12 9William 0 8 8 10 11 data1 data2 data3 12John 2 2 12 13William 0 8 8 二十六、pandas resample 数据重采样数据重采样是将时间序列从一个频率转换至另一个频率的过程,它主要有两种实现方式,分别是降采样和升采样,降采样指将高频率的数据转换为低频率,升采样则与其恰好相反,说明如下: 方法说明降采样将高频率(间隔短)数据转换为低频率(间隔长)。升采样将低频率数据转换为高频率。Pandas 提供了 resample() 函数来实现数据的重采样。 降采样通过 resample() 函数完成数据的降采样,比如按天计数的频率转换为按月计数。 import pandas as pd import numpy as np rng = pd.date_range('1/1/2021',periods=100,freq='D') ts = pd.Series(np.random.randn(len(rng)),index=rng) #降采样后并聚合 ts.resample('M').mean() 输出结果: 12021-01-31 0.210353 22021-02-28 -0.058859 32021-03-31 -0.182952 42021-04-30 0.205254 5Freq: M, dtype: float64 如果您只想看到月份,那么您可以设置kind=period如下所示: ts.resample('M',kind='period').mean() 输出结果: 12021-01 -0.153121 22021-02 0.136231 32021-03 -0.238975 42021-04 -0.309502 5Freq: M, dtype: float64 升采样升采样是将低频率(时间间隔)转换为高频率,示例如下: import pandas as pd import numpy as np #生成一份时间序列数据 rng = pd.date_range('1/1/2021', periods=20, freq='3D') ts = pd.Series(np.random.randn(len(rng)), index=rng) print(ts.head()) #使用asfreq()在原数据基础上实现频率转换 ts.resample('D').asfreq().head() 输出结果: 1升采样前: 22021-01-01 0.608716 32021-01-04 1.097451 42021-01-07 -1.280173 52021-01-10 -0.175065 62021-01-13 1.046831 7Freq: 3D, dtype: float64 8升采样后: 92021-01-01 0.608716 102021-01-02 NaN 112021-01-03 NaN 122021-01-04 1.097451 132021-01-05 NaN 14Freq: D, dtype: float64 频率转换asfreq() 方法不仅能够实现频率转换,还可以保留原频率对应的数值,同时它也可以单独使用,示例如下: index = pd.date_range('1/1/2021', periods=6, freq='T') series = pd.Series([0.0, None, 2.0, 3.0,4.0,5.0], index=index) df = pd.DataFrame({'s':series}) print(df.asfreq("45s")) 输出结果: 1 num 22021-01-01 00:00:00 0.0 32021-01-01 00:00:45 NaN 42021-01-01 00:01:30 NaN 52021-01-01 00:02:15 NaN 62021-01-01 00:03:00 3.0 72021-01-01 00:03:45 NaN 82021-01-01 00:04:30 NaN 插值处理从上述示例不难看出,升采样的结果会产生缺失值,那么就需要对缺失值进行处理,一般有以下几种处理方式: 方法说明pad/ffill用前一个非缺失值去填充缺失值。backfill/bfill用后一个非缺失值去填充缺失值。interpolater('linear')线性插值方法。fillna(value)指定一个值去替换缺失值。下面使用插值方法处理 NaN 值,示例如下: import pandas as pd import numpy as np #创建时间序列数据 rng = pd.date_range('1/1/2021', periods=20, freq='3D') ts = pd.Series(np.random.randn(len(rng)), index=rng) print(ts.resample('D').asfreq().head()) #使用ffill处理缺失值 ts.resample('D').asfreq().ffill().head() 输出结果: 12021-01-01 0.555580 22021-01-02 NaN 32021-01-03 NaN 42021-01-04 -0.079324 52021-01-05 NaN 6Freq: D, dtype: float64 7 8#插值处理,注意对比 92021-01-01 0.555580 102021-01-02 0.555580 112021-01-03 0.555580 122021-01-04 -0.079324 132021-01-05 -0.079324 14Freq: D, dtype: float64 二十七、pandas 分类对象通常情况下,数据集中会存在许多同一类别的信息,比如相同国家、相同行政编码、相同性别等,当这些相同类别的数据多次出现时,就会给数据处理增添许多麻烦,导致数据集变得臃肿,不能直观、清晰地展示数据。 针对上述问题,Pandas 提供了分类对象(Categorical Object),该对象能够实现有序排列、自动去重的功能,但是它不能执行运算。本节,我们了解一下分类对象的使用。 对象创建我们可以通过多种方式创建分类对象,下面介绍以下两种方法: 指定dtype创建import pandas as pds = pd.Series(["a","b","c","a"], dtype="category")print(s)输出结果:10 a21 b32 c43 a5dtype: category6Categories (3, object): [a, b, c]通过上述示例,您可能会注意到,虽然传递给 Series 四个元素值,但是它的类别为 3,这是因为 a 的类别存在重复。pd.Categorical通过 Category 的构造函数,您可以创建一个类别对象。构造函数,如下所示: pandas.Categorical(values, categories, ordered) values:以列表的形式传参,表示要分类的值。ordered:布尔值,默认为 False,若为 Ture,表示对分类的数据进行排序。dtype:返回一个 category 类型,表示分类对象。 示例如下: import pandas as pd #自动按a、b、c分类 cat = pd.Categorical(['a', 'b', 'c', 'a', 'b', 'c']) print(cat) 输出结果: 1[a, b, c, a, b, c] 2Categories (3, object): [a, b, c] 再看一组示例: import pandas as pd cat=pd.Categorical(['a','b','c','a','b','c','d'], ['c', 'b', 'a']) print(cat) 输出结果: 1[a, b, c, a, b, c, NaN] 2Categories (3, object): [c, b, a] 上述示例中,第二个参数值表示类别,当列表中不存在某一类别时,会自动将类别值设置为 NA。 通过指定ordered=True来实现有序分类。示例如下: import pandas as pd cat=pd.Categorical(['a','b','c','a','b','c','d'], ['c', 'b', 'a'],ordered=True) print(cat) #求最小值 print(cat.min()) 输出结果: 1[a, b, c, a, b, c, NaN] 2Categories (3, object): [c < b < a] 3c 获取统计信息对已经分类的数据使用 describe() 方法,您会得到和数据统计相关的摘要信息。 import pandas as pd import numpy as np cat = pd.Categorical(["a", "c", "c", np.nan], categories=["b", "a", "c"]) df = pd.DataFrame({"cat":cat, "s":["a", "c", "c", np.nan]}) print(df.describe()) print(df["cat"].describe()) 输出结果: 1 cat s 2count 3 3 3unique 2 2 4top c c 5freq 2 2 6 7count 3 8unique 2 9top c 10freq 2 11Name: cat, dtype: object 获取类别属性使用obj.categories命令可以获取对象的类别信息。示例如下: import pandas as pd import numpy as np s = pd.Categorical(["a", "c", "c", np.nan], categories=["b", "a", "c"]) print (s.categories) 输出结果: Index(['b', 'a', 'c'], dtype='object') 通过 obj.order 可以获取 order 指定的布尔值: import pandas as pd import numpy as np cat = pd.Categorical(["a", "c", "c", np.nan], categories=["b", "a", "c"]) #False表示未指定排序 print (cat.ordered) 输出结果: 1False 重命名类别要想对类别实现重命名,可以通过 Series.cat.categories 来实现的,示例如下: import pandas as pd s = pd.Series(["a","b","c","a"], dtype="category") #对类名重命名 s.cat.categories = ["Group %s" % g for g in s.cat.categories] print(s.cat.categories) 输出结果: 1Index(['Group a', 'Group b', 'Group c'], dtype='object') 追加新类别使用 s.cat.add_categories() 方法,可以追加新类别。 import pandas as pd s = pd.Series(["a","b","c","a"], dtype="category") #追加新类别 s = s.cat.add_categories([5]) #查看现有类别 print(s.cat.categories) 输出结果: 1Index(['a', 'b', 'c', 5], dtype='object') 删除类别使用 remove_categories() 方法,可以删除不需要的类别。示例如下: import pandas as pd s = pd.Series(["a","b","c","a"], dtype="category") #原序列 print(s) #删除后序列 print(s.cat.remove_categories("a")) 输出结果 10 a 21 b 32 c 43 a 5dtype: category 6Categories (3, object): [a, b, c] 7 80 NaN 91 b 102 c 113 NaN 12dtype: category 13Categories (2, object): [b, c] 分类对象比较在下述两种情况下,我们可以对分类对象进行比较: 当两个类别对象长度相同时,可以进行比较运算;当两个类别的 ordered 均等于 True,并且类别相同时,可以进行比较运算,比如 ==,!=,>,>=,< 和 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |