精华内容
下载资源
问答
  • groupby函数详解

    万次阅读 多人点赞 2019-06-06 13:40:19
    pandas中groupby函数用法详解1 groupby()核心用法2 groupby()语法格式3 groupby()参数说明4 groupby()典型范例 1 groupby()核心用法 (1)根据DataFrame本身的某一列或多列内容进行分组聚合,(a)若按某一列聚合...

    计算各列数据总和并作为新列添加到末尾

    df['Col_sum'] = df.apply(lambda x: x.sum(), axis=1)
    

    计算指定列下每行数据的总和并作为新列添加到末尾

     df_sf['item_sum'] = df_sf.loc[:,['item_1','item_2','item_3']].apply(lambda x:x.sum(),axis=1)   #'item_sum'列计算'item_1','item_2','item_3'三列的总和
    

    计算各行数据总和并作为新行添加到末尾

    df.loc['Row_sum'] = df.apply(lambda x: x.sum())
    

    计算指定列下各行数据总和并作为新行添加到末尾

    MT_fs.loc['总计']=MT_fs.loc[:,['发货量','签收量','激活量','首充']].apply(lambda x: x.sum())  #“总计”表示新增行的“index”
    

    Table1 groupby()的常见用法

    函数适用场景备注
    df.groupby(‘key1’)一列聚合分组键为列名(可以是字符串、数字或其他Python对象)
    df.groupby([‘key1’,‘key2’])多列聚合分组键为列名引入列表list[]
    df[‘data1’].groupby(df[‘key1’]).mean()按某一列进行一重聚合求均值分组键为Series
    A=df[‘订单编号’].groupby([ df[‘运营商’], df[‘分类’], df[‘百度圣卡’] ]).count()按某一列进行多重聚合计数分组键为Series引入列表list[]
    df[‘data1’].groupby([states,years]).mean()分组键与原df无关,而是另外指定的任何长度适当的数组分组键是数组,state和year均为数组

    备注:

    grouped=df['data1'].groupby(df['key1'])    #聚合后不适用配合函数的输出为:<pandas.core.groupby.generic.SeriesGroupBy object at 0x000001FE3D1FE5C0>
    

    这是由于变量grouped是一个GroupBy对象,它实际上还没有进行任何计算,只是含有一些有关分组键df[‘key1’]的中间数据而已,然后我们可以调用配合函数(如:.mean()方法)来计算分组平均值等。
      因此,一般为方便起见可直接在聚合之后+“配合函数”,默认情况下,所有数值列都将会被聚合,虽然有时可能会被过滤为一个子集
      一般,如果对df直接聚合时,
    df.groupby([df['key1'],df['key2']]).mean()分组键为:Series)与df.groupby(['key1','key2']).mean()分组键为:列名)是等价的,输出结果相同。
      但是,如果对df的指定列进行聚合时,
    df['data1'].groupby(df['key1']).mean()分组键为:Series),唯一方式。
    此时,直接使用“列名”作分组键,提示“Error Key”。
       注意:分组键中的任何缺失值都会被排除在结果之外。

    1 groupby()核心用法

    (1)根据DataFrame本身的某一列或多列内容进行分组聚合,(a)若按某一列聚合,则新DataFrame将根据某一列的内容分为不同的维度进行拆解,同时将同一维度的再进行聚合,(b)若按某多列聚合,则新DataFrame将是多列之间维度的笛卡尔积,即:新DataFrame具有一个层次化索引(由唯一的键对组成),例如:“key1”列,有a和b两个维度,而“key2”有one和two两个维度,则按“key1”列和“key2”聚合之后,新DataFrame将有四个group;
    注意:groupby默认是在axis=0上进行分组的,通过设置axis=1,也可以在其他任何轴上进行分组。

    (2)groupby(),根据分组键的不同,有以下4种聚合方法:

    • 分组键为Series
      (a)使用原df的子列作为Series
      df.groupby([ df[‘key1’], df[‘key2’] ]).mean()
      (b)使用自定义的Series
      mapping={‘a’:‘red’,‘b’:‘red’,‘c’:‘blue’,‘d’:‘blue’,‘e’:‘red’,‘f’:‘orange’}
      map_series=pd.Series(mapping)
      people.groupby(map_series,axis=1).count()
    • 分组键为列名
      df.groupby([ ‘key1’,‘key2’ ]).mean()
    • 分组键为数组
      states=np.array([‘Ohio’, ‘California’, ‘California’, ‘Ohio’, ‘Ohio’])
      years=np.array([2004,2005,2006,2005,2006]) #自定义数组
      df[‘data1’].groupby( [ states,years ] ).mean()
    • 分组键为字典
      mapping={‘a’:‘red’,‘b’:‘red’,‘c’:‘blue’,‘d’:‘blue’,‘e’:‘red’,‘f’:‘orange’} #自定义字典
      by_column=people.groupby(mapping,axis=1).sum() #指定axis=1,表示对列数据进行聚合分组
    • 分组键为函数
      例如:传入len函数(可以求取一个字符串长度数组),实现根据字符串的长度进行分组
      people.groupby(len).sum() #将字符串长度相同的行进行求和
    • 分组键为函数和数组、列表、字典、Series的组合
      引入列表list[ ] 将函数跟数组、列表、字典、Series混合使用作为分组键进行聚合,因为任何东西最终都会被转换为数组
      key_list=[‘one’,‘one’,‘one’,‘two’,‘two’] #自定义列表,默认列表顺序和df的列顺序一致
      people.groupby([ len,key_list ]).min()
    • 分组键为具有多重列索引df 的列索引层次
      hier_df.groupby(level=‘cty’,axis=1).count() #利用参数level,指明聚合的层级
      (3)常用配合函数/方法
    1. 打印出按某一指定列进行聚合的DataFrame:
    for i in df.groupby('key1'):
        print(i)
    
    1. 按某一指定列进行聚合的DataFrame:

    Table1 groupby()的配合函数

    函数适用场景备注
    .mean()均值
    .count()计数
    .min()最小值
    .mean().unstack()求均值,聚合表的层次索引不堆叠
    .size()计算分组大小GroupBy的size方法,将返回一个含有分组大小的Series
    .apply()
    .agg()

    (4)对聚合后的数据片段,进行字典、列表等格式转化

    • 将数据片段转为字典
    pieces=pieces=dict(list(df.groupby('key1')))
    
    • 将数据片段转为列表
    pieces=list(df.groupby('key1'))
    

    (5)利用groupby,根据dtypes对列进行分组,此时需指定axis=1,否则,groupby默认根据axis=0进行分组,而行数据由于类型不统一,故无法根据dtypes对列进行分组,结果为空。
    (6)可使用一个/组列名,或者一个/组字符串数组对由DataFrame产生的GroupBy对象,进行索引,从而实现选取部分列进行聚合的目的即:

    1)根据key1键对data1列数据聚合
    df.groupby('key1')['data1'].mean()
    #或者
    df['data1'].groupby(df['key1']).mean()    #或者df['data1'].groupby([df['key1']]).mean() ,当按多个层次聚合时引入列表,故单层次用列表也无妨
    >>>
    key1
    a    -0.048502
    b     0.053162
    Name: data1, dtype: float64
    (2)根据key1键对data2列数据聚合
    df.groupby('key1')['data2'].mean()
    #或者
    df['data2'].groupby(df['key1']).mean()
    >>>
    key1
    a     -0.533444
    b     -0.948798
    Name: data2, dtype: float64
    (3)根据key1键对data2列数据聚合,当对多列数据如data1和data2根据某个键入key1聚合分组时,组引入列表['data1','data2'],此处对data2外加中括号是一个意思,只是影响输出格式。
    df.groupby('key1')[['data2']].mean()
    #或者df[['data2']].groupby(df['key1']).mean()
    >>>
    	 data2
    key1	
    a	-0.533444
    b	-0.9487984)根据key1键对data1和data2列数据聚合
    df.groupby('key1')[['data1','data2']].mean()
    #或者
    df[['data1','data2']].groupby(df['key1']).mean()
    >>>
    	   data1	data2
    key1		
    a	 -0.048502	-0.533444
    b	  0.053162	-0.9487985)根据多个键key1、key2对data2列数据聚合
    df.groupby(['key1','key2'])['data2'].mean()
    #或者
    df['data2'].groupby([df['key1'],df['key2']]).mean()
    >>>
    key1  key2
    a     one    -1.391653
          two     1.182974
    b     one    -1.707349
          two    -0.190247
    Name: data2, dtype: float64
    

    2 groupby()语法格式

    DataFrame.groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=False, observed=False, **kwargs)
    

    3 groupby()参数说明

    by : mapping, function, label, or list of labels
    Used to determine the groups for the groupby. If by is a function, it’s called on each value of the object’s index. If a dict or Series is passed, the Series or dict VALUES will be used to determine the groups (the Series’ values are first aligned; see .align() method). If an ndarray is passed, the values are used as-is determine the groups. A label or list of labels may be passed to group by the columns in self. Notice that a tuple is interpreted a (single) key.

    axis : {0 or ‘index’, 1 or ‘columns’}, default 0
    Split along rows (0) or columns (1).

    level : int, level name, or sequence of such, default None
    If the axis is a MultiIndex (hierarchical), group by a particular level or levels.

    as_index : bool, default True
    For aggregated output, return object with group labels as the index. Only relevant for DataFrame input. as_index=False is effectively “SQL-style” grouped output.

    sort : bool, default True
    Sort group keys. Get better performance by turning this off. Note this does not influence the order of observations within each group. Groupby preserves the order of rows within each group.

    group_keys : bool, default True
    When calling apply, add group keys to index to identify pieces.

    squeeze : bool, default False
    Reduce the dimensionality of the return type if possible, otherwise return a consistent type.

    observed : bool, default False
    This only applies if any of the groupers are Categoricals. If True: only show observed values for categorical groupers. If False: show all values for categorical groupers.

    New in version 0.23.0.

    **kwargs
    Optional, only accepts keyword argument ‘mutated’ and is passed to groupby.

    4 groupby()典型范例

    范例一:根据DataFrame本身的某一列或多列内容进行分组聚合

    #创建原始数据集
    import pandas as pd
    import numpy as np
    
    df=pd.DataFrame({'key1':['a','a','b','b','a'],
                     'key2':['one','two','one','two','one'],
                      'data1':np.random.randn(5),
                      'data2':np.random.randn(5)})
    #'key1':['a','a','b','b','a']亦可写作'key1':list('aabba'),完成列表的创建
    >>> df
       key1	 key2	    data1	  data2
    0	a	 one	  -0.484689	  -3.105627
    1	a	 two	  0.033929	  1.182974
    2	b	 one	  1.067201	  -1.707349
    3	b	 two	  -0.960876	  -0.190247
    4	a	 one	  0.305254	  0.322322
    #(1)按指定的某一列进行聚合
    for i in df.groupby('key1'):
        print(i)
    >>>
    ('a',   key1   key2     data1      data2
    0        a     one     -0.484689   -3.105627
    1        a     two     0.033929    1.182974
    4        a     one     0.305254    0.322322)
    ('b',   key1   key2     data1      data2
    2        b     one     1.067201    -1.707349
    3        b     two     -0.960876   -0.190247)
    #(2)按多列进行聚合,新的DataFrame是多列之间维度的笛卡尔积
    for i in df.groupby(['key1','key2']):
        print(i)
    >>>
    (('a', 'one'),   key1    key2     data1      data2
          0          a       one      -0.484689  -3.105627
          4          a       one      0.305254   0.322322)
    (('a', 'two'),   key1    key2     data1     data2
          1          a       two      0.033929   1.182974)
    (('b', 'one'),   key1    key2     data1     data2
          2          b       one      1.067201 -1.707349)
    (('b', 'two'),   key1   key2     data1     data2
          3          b       two      -0.960876 -0.190247)
    #(3) 按key1进行分组,并计算data1列的平均值
    df1=df['data1'].groupby(df['key1']).mean()
    >>>
    key1
    a       -0.048502
    b       0.053162
    #(4) 按key1、key2进行分组,并计算data1列的平均值,聚合表不堆叠
    #将数据从“花括号”格式转为“表格”格式,unstack即“不要堆叠”
    df2=df['data1'].groupby([df['key1'],df['key2']]).mean().unstack()
    >>>df2
    key2	one	        two
    key1		
    a	    -0.089718	 0.033929
    b	    1.067201	 -0.960876
    #(5)分组键可以是与原df无关的,另外指定的任何长度适当的数组,新数组按列表顺序分别与df[col_1]的数据一一对应。
    states=np.array(['Ohio', 'California', 'California', 'Ohio', 'Ohio'])
    years=np.array([2004,2005,2006,2005,2006])
    df['data1'].groupby([states,years]).mean()
    >>>
    California  2005    0.033929
                2006    1.067201
    Ohio        2004   -0.484689
                2005   -0.960876
                2006    0.305254
    #用到GroupBy的size方法,它可以返回一个含有分组大小的Series
    df.groupby(['key1','key2']).size()
    >>>
          key1  key2
    a     one     2
          two     1
    b     one     1
          two     1
    

    范例二:利用for循环,对分组进行迭代

    #原始数据集与范例一相同
    #对一列聚合,使用for循环进行分组迭代
    for name,group in df.groupby('key1'):
        print(name)
        print(group)
    >>>
    a
      key1 key2     data1     data2
    0    a  one -0.484689 -3.105627
    1    a  two  0.033929  1.182974
    4    a  one  0.305254  0.322322
    b
      key1 key2     data1     data2
    2    b  one  1.067201 -1.707349
    3    b  two -0.960876 -0.190247
    #若仅使用一个变量name,会影响输出结果的索引层次表达方式,且结果为元组
    for name in df.groupby('key1'):
        print(name)
    >>>
    ('a',   key1 key2     data1     data2
    0    a  one -0.484689 -3.105627
    1    a  two  0.033929  1.182974
    4    a  one  0.305254  0.322322)
    ('b',   key1 key2     data1     data2
    2    b  one  1.067201 -1.707349
    3    b  two -0.960876 -0.190247)
    #对于多重键的情况,元组的第一个元素将会是由键值组成的元组,所以for循环的第一个变量用元组(k1,k2):
    for (k1,k2),group in df.groupby(['key1','key2']):
        print(k1,k2)
        print(group)
    >>>
    a one
      key1 key2     data1     data2
    0    a  one -0.484689 -3.105627
    4    a  one  0.305254  0.322322
    a two
      key1 key2     data1     data2
    1    a  two  0.033929  1.182974
    b one
      key1 key2     data1     data2
    2    b  one  1.067201 -1.707349
    b two
      key1 key2     data1     data2
    3    b  two -0.960876 -0.190247
    #对于多重键的情况,若for循环的第一个变量不用元组(k1,k2),而是普通变量name,则输出结果的层次索引将为元组格式
    for name,group in df.groupby(['key1','key2']):
        print(name)
        print(group)
    >>>
    ('a', 'one')
      key1 key2     data1     data2
    0    a  one -0.484689 -3.105627
    4    a  one  0.305254  0.322322
    ('a', 'two')
      key1 key2     data1     data2
    1    a  two  0.033929  1.182974
    ('b', 'one')
      key1 key2     data1     data2
    2    b  one  1.067201 -1.707349
    ('b', 'two')
      key1 key2     data1     data2
    3    b  two -0.960876 -0.190247
    

    范例三:对聚合后的数据片段,进行格式类型转化

    #将数据片段转为字典
    pieces=dict(list(df.groupby('key1')))
    >>>
    pieces
    {'a':   key1  key2     data1     data2
     0       a   one     -0.484689 -3.105627
     1       a   two      0.033929  1.182974
     4       a   one      0.305254  0.322322, 'b':   key1 key2     data1     data2
     2       b   one      1.067201 -1.707349
     3       b   two     -0.960876 -0.190247}
     >>>
     pieces['b']    #选取片段
        key1	key2	data1	    data2
    2	b	    one	    1.067201	-1.707349
    3	b	    two	    -0.960876	-0.190247
    #将数据片段转为列表
    pieces=list(df.groupby('key1'))
    >>>
    pieces
    [('a',   key1 key2     data1     data2
      0       a   one     -0.484689 -3.105627
      1       a   two      0.033929  1.182974
      4       a   one      0.305254  0.322322), ('b',   key1 key2     data1     data2
      2       b   one      1.067201 -1.707349
      3       b   two     -0.960876 -0.190247)]
    

    范例四:利用groupby,根据dtypes对列进行分组,此时,需指定axis=1,否则,groupby默认根据axis=0进行分组,而行数据由于类型不统一,故无法根据dtypes对列进行分组

    #df.dtypes用于确定df的数据类型
    df.dtypes
    >>>
    key1      object
    key2      object
    data1    float64
    data2    float64
    dtype: object
    #将聚合后df转化为字典格式,后根据df的数据类型对列进行分组
    grouped=df.groupby(df.dtypes,axis=1)
    dict(list(grouped))
    >>>
    {dtype('float64'):       data1     data2
                          0 -0.484689 -3.105627
                          1  0.033929  1.182974
                          2  1.067201 -1.707349
                          3 -0.960876 -0.190247
                          4  0.305254  0.322322, dtype('O'):   key1  key2
                                                           0    a   one
                                                           1    a   two
                                                           2    b   one
                                                           3    b   two
                                                           4    a   one}
    #若不指定axis=1,则默认groupby根据行数据按dtypes进行分组
    grouped1=df.groupby(df.dtypes)
    dict(list(grouped1))
    >>>
    {}    #由于行数据不统一,故按dtypes分组时,为空
    #将聚合数据片段转化为list类型
    list(grouped)
    >>>
    [(dtype('float64'),       data1     data2
                           0  -0.484689 -3.105627
                           1   0.033929  1.182974
                           2   1.067201 -1.707349
                           3  -0.960876 -0.190247
                           4   0.305254  0.322322), (dtype('O'),    key1  key2
                                                                 0    a  one
                                                                 1    a  two
                                                                 2    b  one
                                                                 3    b  two
                                                                 4    a  one)]
                                                                 
    

    范例五:根据自定义字典、自定义列表、自定义Series、函数或者函数与自定义数组、列表、字典、Series的组合,作为分组键进行聚合

    #创建原始数据集
    people=pd.DataFrame(np.random.randn(5,5),columns=list('abcde'),index=['Joe','Steve','Wes','Jim','Travis'])
    people
    >>>
                a	        b	        c	       d	       e
    Joe 	-0.350379	-2.216265	-1.922898	0.655574	0.512573
    Steve	-1.212107	-1.040184	-0.659978	-0.277454	0.613489
    Wes	    -1.624845	-0.432863	-0.211577	0.310541	2.138030
    Jim	     2.038365	-0.237121	-0.392664	-0.480918	1.566855
    Travis	-0.345361	-0.653787	-0.299217	1.019871	0.511216
    #利用people.ix[2:3,['b','c']]=np.nan,将第2,3行,第b,c列的数据置为空
    people.ix[2:3,['b','c']]=np.nan
    >>>
    people
                a	        b	        c	       d	      e
    Joe	    -0.350379	-2.216265	-1.922898	 0.655574	0.512573
    Steve	-1.212107	-1.040184	-0.659978	-0.277454	0.613489
    Wes	    -1.624845	   NaN	       NaN	     0.310541	2.138030
    Jim	     2.038365	-0.237121	-0.392664	-0.480918	1.566855
    Travis	-0.345361	-0.653787	-0.299217	 1.019871	0.511216
    # 假设已知列的分组关系,并希望根据分组计算列的总计:
    #创建分组的映射字典
    mapping={'a':'red','b':'red','c':'blue','d':'blue','e':'red','f':'orange'}
    mapping
    >>>
    {'a': 'red', 'b': 'red', 'c': 'blue', 'd': 'blue', 'e': 'red', 'f': 'orange'}
    type(mapping)
    >>>
    dict
    #将这个字典传给groupby即可,由于是按列进行分组,指定axis=1
    by_column=people.groupby(mapping,axis=1).sum()
    by_column
    >>>
    	        blue	red
    Joe	       -1.267323	-2.054071
    Steve	   -0.937431	-1.638802
    Wes	        0.310541	 0.513184
    Jim	       -0.873581	 3.368099
    Travis	    0.720653	-0.487932
    #用自定义Series作为分组键进行聚合,则pandas会检查Series以确保其索引跟分组轴是对齐的
    #自定义Series作为分组键
    map_series=pd.Series(mapping)
    >>>
    map_series
    a       red
    b       red
    c      blue
    d      blue
    e       red
    f    orange
    dtype: object
    #用自定义Series作为分组键聚合
    people.groupby(map_series,axis=1).count()
    >>>
           blue	red
    Joe	    2	3
    Steve	2	3
    Wes	    1	2
    Jim	    2	3
    Travis	2	3
    #用函数作分组键,进行分组,需传入len函数(可以求取一个字符串长度数组),实现根据人名的长度进行分组
    people.groupby(len).sum()   #将名字长度相同的行求和
    >>>
            a	        b	         c	        d	       e
    3	0.063140	-2.453386	-2.315561	0.485198	4.217458
    5	-1.212107	-1.040184	-0.659978	-0.277454	0.613489
    6	-0.345361	-0.653787	-0.299217	1.019871	0.511216
    #将函数和数组、列表、字典、Series组合作为分组键,进行聚合
    key_list=['one','one','one','two','two']   #自定义列表,默认列表的字符串顺序和df的列顺序一致
    people.groupby([len,key_list]).min()
    >>>
                 a	        b	        c	        d	       e
    3	one	 -1.624845	-2.216265	-1.922898	0.310541	0.512573
        two	  2.038365	-0.237121	-0.392664	-0.480918	1.566855
    5	one	 -1.212107	-1.040184	-0.659978	-0.277454	0.613489
    6	two	 -0.345361	-0.653787	-0.299217	1.019871	0.511216
    

    范例六:df含有多重列索引的聚合分组

    #根据df的多重列索引的层次级别分组聚合
    #自定义列层次索引
    columns=pd.MultiIndex.from_arrays([['US','US','US','JP','JP'],[1,3,5,1,3]],names=['cty','tenor'])
    >>>
    columns
    MultiIndex(levels=[['JP', 'US'], [1, 3, 5]],
               codes=[[1, 1, 1, 0, 0], [0, 1, 2, 0, 1]],
               names=['cty', 'tenor'])
    #创建包含多重列索引的原始数据集
    hier_df=pd.DataFrame(np.random.randn(4,5),columns=columns)
    >>>
    hier_df
    cty	    US	        JP
    tenor	  1	          3	         5	         1	        3
    0	  0.023254	 -0.271758	-0.129695	-1.003850	0.600698
    1	  -0.076856	 0.696218	-1.054670	-0.232982	0.641908
    2	  0.211017	 0.481233	-0.289600	0.794614	-0.910464
    3	  1.069144	 0.358034	0.169202	-1.910069	0.769219
    #按列索引层次进行分组聚合
    hier_df.groupby(level='cty',axis=1).count()    #利用参数level,指明聚合的层级
    >>>
    cty	JP	US
    0	2	3
    1	2	3
    2	2	3
    3	2	3
    
    #"盲投"DataFrame按照“号码归属省”对指定4列“'发货量','签收量','激活量','首充'”进行聚合
    functions=['count']
    MT_fs_grouped=MT_data.groupby(['号码归属省'])
    MT_fs=MT_fs_grouped['发货量','签收量','激活量','首充'].agg(functions)
    MT_fs=pd.DataFrame(MT_fs)
    MT_fs.reset_index(inplace=True)   #将聚合表的index转为普通列
    #对聚合表增加“各列统计求和”的行,同时指定参与求和的列,即“号码归属省”列需排除;
    MT_fs.loc['总计']=MT_fs.loc[:,['发货量','签收量','激活量','首充']].apply(lambda x: x.sum())
    MT_fs.loc['总计',['号码归属省']]='总计'  #补全“省份”最后一行的“总计”名称
    

    参考链接:https://www.cnblogs.com/huiyang865/p/5577772.html

    5 groupby常见的调用函数

    • 描述组内数据的基本统计量:A.groupby("性别").describe().unstack()
    • 组内均值计算:A.groupby("性别").mean()
    • 我们还可以一次运用多个函数计算:A.groupby( ["班级","性别"]).agg([np.sum, np.mean, np.std]) # 一次计算了三个
    • 按照【生日】的【年份】进行分组,看看有多少人是同龄?
      A[“生日”] = pd.to_datetime(A[“生日”],format ="%Y/%m/%d") # 转化为时间格式
      A.groupby(A["生日"].apply(lambda x:x.year)).count() # 按照【生日】的【年份】分组
      在这里插入图片描述

    参考链接:python中groupby函数主要的作用是进行数据的分组以及分组后地组内运算!

    展开全文
  • Python Pandas Groupby教程

    千次阅读 2020-07-15 12:15:54
    In this Pandas group by we are going to learn how to organize Pandasdataframes by groups. More specifically, we are going to learn how to group by one and multiple columns. Furthermore, we are going ....

    In this Pandas group by we are going to learn how to organize Pandas dataframes by groups. More specifically, we are going to learn how to group by one and multiple columns. Furthermore, we are going to learn how calculate some basics summary statistics (e.g., mean, median), convert Pandas groupby to dataframe, calculate the percentage of observations in each group, and many more useful things.

    在这个熊猫小组中,我们将学习如何按组组织熊猫数据帧。 更具体地说,我们将学习如何按一列和多列分组。 此外,我们将学习如何计算一些基本摘要统计信息(例如,均值,中位数),将Pandas groupby转换为数据框,计算每个组中观察值的百分比以及更多有用的东西。

    First of all we are going to import pandas as pd, and read a CSV file, using the read_csv method, to a dataframe. In the example below, we use index_col=0 because the first row in the dataset is the index column.

    首先,我们将以pd格式导入熊猫,并使用read_csv方法将CSV文件读取到数据框。 在下面的示例中,我们使用index_col = 0,因为数据集中的第一行是索引列。

    import pandas as pd
    
    data_url = 'http://vincentarelbundock.github.io/Rdatasets/csv/carData/Salaries.csv'
    df = pd.read_csv(data_url, index_col=0)
    
    df.head()
    
    

    ()

    We used Pandas head to se the first 5 rows of our dataframe. In the image above we can see that we have, at least, three variables that we can group our data by. That is, we can group our data by “rank”, “discipline”, and “sex”. Of course, we could also group it by yrs.since.phd or yrs.service but it may be a lot of groups.  As previously mentioned we are going to use Pandas groupby to group a dataframe based on one, two, three, or more columns.

    我们使用Pandas head来获取数据帧的前5行。 在上图中,我们可以看到至少有三个变量可以对数据进行分组。 也就是说,我们可以按“等级”,“学科”和“性别”对数据进行分组。 当然,我们也可以按yrs.since.phd或yrs.service对其进行分组,但可能会有很多分组。 如前所述,我们将使用Pandas groupby根据一,二,三或更多列对数据帧进行分组。

    Data can be loaded from other file formats as well (e.g., Excel, HTML, JSON):

    数据也可以从其他文件格式(例如Excel,HTML,JSON)加载:

    Python Pandas Groupby示例 (Python Pandas Groupby Example)

    We are starting with the simplest example; grouping by one column. In the Pandas groupby example below we are going to group by the column “rank”.

    我们从最简单的例子开始; 按一列分组。 在下面的Pandas groupby示例中,我们将按“等级”列进行分组。

    There are many different methods that we can use on Pandas groupby objects (and Pandas dataframe objects). All available methods on a Python object can be found using this code:

    我们可以对Pandas groupby对象(和Pandas dataframe对象)使用许多不同的方法。 可以使用以下代码找到Python对象上的所有可用方法:

    import IPython
    
    # Grouping by one factor
    df_rank = df.groupby('rank')
    
    # Getting all methods from the groupby object:
    meth = [method_name for method_name in dir(df_rank)
     if callable(getattr(df_rank, method_name)) & ~method_name.startswith('_')]
    
    # Printing the result
    print(IPython.utils.text.columnize(meth))
    

     

    Note, that in the code example above we also import IPython to print the list in columns. In the following examples we are going to use some of these methods. First, we can print out the groups by using the groups method to get a dictionary of groups:

    请注意,在上面的代码示例中,我们还导入了IPython以按列打印列表。 在以下示例中,我们将使用其中一些方法。 首先,我们可以使用groups方法打印组,以获取组字典:

    df_rank.groups
    

     

    We can also use the groupby method get_group to filter the grouped data. In the next code example we are going to select the Assistant Professor group (i.e., “AsstProf”).

    我们还可以使用groupby方法get_group过滤分组的数据。 在下一个代码示例中,我们将选择“助理教授”组(即“ AsstProf”)。

    # Get group
    df_rank.get_group('AsstProf').head()
    

     

    熊猫Groupby Count (Pandas Groupby Count)

    If we want to find out how big each group is (e.g., how many observations in each group), we can use use .size() to count the number of rows in each group:

    如果我们想找出每个组的大小(例如,每个组中有多少个观测值),可以使用.size()来计算每个组中的行数:

    df_rank.size()
    
    # Output:
    #
    # rank
    # AssocProf     64
    # AsstProf      67
    # Prof         266
    # dtype: int64
    

     

    Additionally, we can also use Pandas groupby count method to count by group(s) and get the entire dataframe. If we don’t have any missing values the number should be the same for each column and group. Thus, this is a way we can explore the dataset and see if there are any missing values in any column.

    此外,我们还可以使用Pandas的groupby count方法按组进行计数并获取整个数据框。 如果我们没有任何缺失值,则每个列和每个组的编号应相同。 因此,这是一种我们可以浏览数据集并查看任何列中是否缺少任何值的方法。

    df_rank.count()
    

     

    That was how to use Pandas size to count the number of rows in each group. We will return to this, later, when we are grouping by multiple columns. Now we are going to In some cases we may want to find out the number of unique values in each group. This can be done using the groupby method nunique:

    这就是使用熊猫大小来计算每个组中的行数的方法。 稍后,当我们按多列分组时,我们将返回到此。 现在,在某些情况下,我们可能想要找出每个组中唯一值的数量。 这可以使用groupby方法nunique来完成:

    df_rank.nunique()
    

     

    As can be seen in the the last column (salary) there are 63 Associate Professors, 53 Assistant Proffessors, and 261 Professors in the dataset. In this example we have a complete dataset and we can see that some have the same salary (e.g., there are 261 unique values in the column salary for Professors). As we will see if we have missing values in the dataframe we would get a different result. In the next example we are using Pandas mask method together with NumPy’s random.random to insert missing values (i.e., np.NaN) in 10% of the dataframe:

    从最后一栏(薪水)可以看出,数据集中有63位副教授,53位助理教授和261位教授。 在此示例中,我们具有完整的数据集,我们可以看到其中一些具有相同的薪水(例如,“教授”列中的薪水有261个唯一值)。 我们将看到如果数据框中缺少值,我们将得到不同的结果。 在下一个示例中,我们将Pandas遮罩方法与NumPy的random.random一起使用,以在10%的数据帧中插入缺失值(即np.NaN):

    df_null = df.mask(np.random.random(df.shape) < .1)
    df_null.isnull().sum().reset_index(name='N Missing Values')
    

     

    Note, we used the reset_index method above to get the multi-level indexed grouped dataframe to become a single indexed. In the particular example, above, we used the parameter name to name the count column (“N Missing Values”). This parameter, however, can only be used on Pandas series objects and not dataframe objects.

    注意,我们使用了上面的reset_index方法来获取多级索引分组数据帧,使其成为单个索引。 在上面的特定示例中,我们使用参数名称来命名计数列(“ N个缺失值”)。 但是,此参数只能在Pandas系列对象上使用,而不能在dataframe对象上使用。

    That said, let’s return to the example; if we run the same code as above (counting unique values by group) we can see that it will not count missing values:

    就是说,让我们回到例子。 如果我们运行与上面相同的代码(按组计算唯一值),我们可以看到它不会计算缺失值:

    df_null.groupby('rank').nunique()
    

     

    That is, we don’t get the same numbers in the two tables because of the missing values. In the following examples we are going to work with Pandas groupby to calculate the mean, median, and standard deviation by one group.

    也就是说,由于缺少值,我们在两个表中没有得到相同的数字。 在以下示例中,我们将与Pandas groupby一起计算一组的均值,中位数和标准差。

    熊猫Groupby Mean (Pandas Groupby Mean)

    If we want to calculate the mean salary grouped by one column (rank, in this case) it’s simple. We just use Pandas mean method on the grouped dataframe:

    如果要计算按一列分组的平均工资(在这种情况下为等级),这很简单。 我们只对分组数据框使用熊猫均值法:

    df_rank['salary'].mean().reset_index()
    

     

     

    Having a column named salary may not be useful. For instance, if someone else are going to see the table they may not know that it’s the mean salary for each group. Luckily, we can add the rename method to the above code to rename the columns of the grouped data:

    具有名为薪水的列可能没有用。 例如,如果其他人要看表,他们可能不知道这是每个组的平均工资。 幸运的是,我们可以在上面的代码中添加重命名方法来重命名分组数据的列:

    df_rank['salary'].mean().reset_index().rename(
        columns={'rank':'Rank','salary' : 'Mean Salary'})
    

     

    在熊猫中使用groupby方法得出的组的中位数 (Median Score of a Group Using the groupby Method in Pandas)

    Now lets group by disciplne of the academic and find the median salary in the next Pandas groupby example

    现在让学者按学科分组,并在下一个熊猫分组示例中找到工资中位数

    df.groupby('rank')['salary'].median().reset_index().rename(
        columns={'rank':'Rank','salary' : 'MedianSalary'})
    

     

    使用Pandas Groupby按组汇总数据 (Aggregate Data by Group using Pandas Groupby)

    Most of the time we want to have our summary statistics in the same table. We can calculate the mean and median salary, by groups, using the agg method. In this next Pandas groupby example we are also adding the minimum and maximum salary by group (rank):

    大多数时候,我们希望将汇总统计信息放在同一张表中。 我们可以使用agg方法按组计算平均工资和中位数工资。 在下一个Pandas groupby示例中,我们还将按组(排名)添加最低和最高薪水:

    df_rank['salary'].agg(['mean', 'median', 
                                      'std', 'min', 'max']).reset_index()
    

     

    A very neat thing with Pandas agg method is that we can write custom functions and pass them along. Let’s say that we wanted, instead of having one column for min salary and one column for max salary, to have a column with salary range:

    使用Pandas agg方法的一件非常整洁的事情是,我们可以编写自定义函数并将其传递。 假设我们想要的是,而不是有一栏用于最低薪水,而一栏用于最高薪水,而不是有一栏的薪水范围:

    def salary_range(df):
        mini = df.min()
        maxi = df.max()
        rang = '%s - %s' % (mini, maxi)
        
        return rang
    
    df_descriptive = df_rank['salary'].agg(['mean', 'median', 'std', salary_range]).reset_index()
    

     

    Here, however, the output will have the name of the methods/functions used. That is, we will have a column named ‘salary_range’ and we are going to rename this column:

    但是,此处的输出将具有所用方法/功能的名称。 也就是说,我们将有一个名为“ salary_range”的列,我们将重命名该列:

    # Renaming Pandas Dataframe Columns
    df_descriptive.rename(columns={'rank':'Rank', 'mean':'Mean', 'median':'Median', 
                                   'std':'Standard Deviation', 'salary_range':'Range'})
    

     

    Furthermore, it’s possible to use methods from other Python packages such as SciPy and NumPy. For instance, if we wanted to calculate the harmonic and geometric mean we can use SciPy:

    此外,可以使用其他Python软件包中的方法,例如SciPy和NumPy。 例如,如果我们要计算谐波和几何平均值,则可以使用SciPy:

    from scipy.stats.mstats import gmean, hmean
    
    df_descriptive = df_rank['salary'].agg(['mean', 'median', hmean, gmean]).reset_index()
    df_descriptive
    

    More about doing descriptive statistics using Pyton:

    有关使用Pyton进行描述性统计的更多信息:

    熊猫分组比多列 (Pandas Groupby Multiple Columns)

    In this section we are going to continue using Pandas groupby but grouping by many columns. In the first example we are going to group by two columns and the we will continue with grouping by two columns, ‘discipline’ and ‘rank’. To use Pandas groupby with multiple columns we add a list containing the column names. In the example below we also count the number of observations in each group:

    在本节中,我们将继续使用Pandas groupby,但将按许多列进行分组。 在第一个示例中,我们将按两列分组,而我们将继续按“纪律”和“排名”两列进行分组。 要将Pandas groupby与多个列一起使用,我们添加一个包含列名的列表。 在下面的示例中,我们还计算每组中的观察次数:

    df_grp = df.groupby(['rank', 'discipline'])
    df_grp.size().reset_index(name='count')
    

     

    Again, we can use the get_group method to select groups. However, in this case we have to input a tuple and select two groups:

    同样,我们可以使用get_group方法选择组。 但是,在这种情况下,我们必须输入一个元组并选择两个组:

    # Get two groups
    df_grp.get_group(('AssocProf', 'A')).head()
    

     

    熊猫Groupby计算多个组 (Pandas Groupby Count Multiple Groups)

    In the next groupby example we are going to calculate the number of observations in three groups (i.e., “n”). We have to start by grouping by “rank”, “discipline” and “sex” using groupby. As with the previous example (groupby one column) we use the method size to calculate the n and reset_index, with the parameter name=”n”, to get the series to a dataframe:

    在下一个分组示例中,我们将计算三组(即“ n”)中的观察数。 我们必须首先使用groupby按“等级”,“纪律”和“性别”分组。 与前面的示例(groupby一列)一样,我们使用方法大小来计算n和reset_index(参数名称为“ n”),以将序列获得数据框:

    df_3grps = df.groupby(['rank', 'discipline', 'sex'])
    df_n_per_group = df_3grps.size().reset_index(name='n')
    

    Now we can continue and calculate the percentage of men and women in each rank and discipline. In this, and the next, Pandas groupby example we are going to use the apply method together with the lambda function.

    现在,我们可以继续计算每个级别和学科中男女的比例。 在此以及下一个Pandas groupby示例中,我们将结合使用apply方法和lambda函数。

    perc = df.groupby(['rank', 'discipline', 'sex'])['salary'].size()
    
    # Give the percentage on the level of Rank:
    percbyrank = perc.groupby(level=0).apply(lambda x: 100 * x / float(x.sum()))
    
    print(percbyrank)
    print('Total percentage in group AssocProf. ',
          percbyrank.reset_index().query('rank == "AssocProf"')['salary'].sum())
    

     

    Note, in the last line of code above we calculate the total of % for the group AssocProf and it’s 100, which is good. We are going to continue with calculating the percentage of men and women in each group (i.e., rank and discipline). In the next code we have to summarize the total (n=397). We can, for instance, see that there are more male professors regardless of discipline.

    请注意,在上面的代码的最后一行中,我们计算了AssocProf组的百分比总数,它是100,这很好。 我们将继续计算每个组中男性和女性的百分比(即等级和纪律)。 在下一个代码中,我们必须总结总计n (n = 397)。 例如,我们可以看到,无论纪律如何,都有更多的男教授。

    n = perc.reset_index()['salary'].sum()
    totalperc =  perc.groupby(level=0).apply(lambda x: 100 * x / N).reset_index(name='% of total n')
    totalperc.reset_index()
    

    如何将Pandas Groupby转换为Dataframe (How to convert a Pandas groupby to Dataframe)

    When dealing with multiple groups and Pandas groupby we get a GroupByDataFrame object. Let’s use type to see what type a grouped object have:

    当处理多个组和Pandas groupby时,我们得到一个GroupByDataFrame对象。 让我们使用type来查看分组对象的类型:

    df_rn = df.groupby(['rank', 'discipline']).mean()
    

    Furthermore, if we use the index method we can see that it is MultiIndex:

    此外,如果使用index方法,我们可以看到它是MultiIndex:

    df_rn.index
    

     

    It’s easy to convert the Pandas groupby to dataframe; we have actually already done it. In this example, however, we are going to calculate the mean values per the three groups. Furthermore, we are going to add a suffix to each column and use reset_index to get a dataframe.

    将Pandas groupby转换为数据框很容易; 我们实际上已经做到了。 但是,在此示例中,我们将计算这三个组的平均值。 此外,我们将为每列添加一个后缀,并使用reset_index获取数据框。

    df_rn = df_rn.add_suffix('_Mean').reset_index()
    type(df_rn)
    
    # Output: pandas.core.frame.DataFrame
    

     

    熊猫groupby agg与多个组 (Pandas groupby agg with Multiple Groups)

    In this last section we are going use agg, again. We are not going into detail on how to use mean, median, and other methods to get summary statistics, however. This is because it’s basically the same as for grouping by n groups and it’s better to get all the summary statistics in one table.

    在最后一部分中,我们将再次使用agg。 但是,我们不会详细介绍如何使用均值,中位数和其他方法来获取摘要统计信息。 这是因为它基本上与按n个组分组相同,并且最好将所有摘要统计信息聚集在一个表中。

    That is, we are going to calculate mean, median, and standard deviation using the agg method. In this groupby example we are also adding the summary statistics (i.e., “mean”, “median”, and “std”) to each column. Otherwise we will get a multi-level indexed result like the image below:

    也就是说,我们将使用agg方法计算平均值,中位数和标准差。 在此groupby示例中,我们还将摘要统计信息(即“均值”,“中位数”和“ std”)添加到每一列。 否则,我们将获得多级索引结果,如下图所示:

    If we use Pandas columns and the method ravel together with list comprehension we can add the suffixes to our column name and get another table. Note, in the example code below we only print the first 7 columns. In fact, with many columns it may be better to keep the result multi-level indexed.

    如果我们将Pandas列和ravel方法与列表理解一起使用,则可以将后缀添加到我们的列名中并获得另一个表。 注意,在下面的示例代码中,我们仅打印前7列。 实际上,对于许多列,最好将结果保留为多级索引。

    df_stats = df.groupby(['rank', 'discipline', 'sex']).agg(['mean', 'median', 'std'])
    df_stats.columns = ["_".join(x) for x in df_stats.columns.ravel()]
    
    df_stats.iloc[:,0:6].reset_index()
    

    Note, if we wanted an output as the first image we just remove the second line above (“df_stats.columns = …”). Additionally, as previous mentioned, we can also use custom functions, NumPy and SciPy methods when working with groupby agg. Just scroll back up and look at those examples, for grouping by one column, and apply them to the data grouped by multiple columns. More information of the different methods and objects used here can be found in the Pandas documentation.

    注意,如果我们希望将输出作为第一张图像,则只需删除上面的第二行(“ df_stats.columns =…”)。 此外,如前所述,在使用groupby agg时,我们还可以使用自定义函数NumPy和SciPy方法。 只需向上滚动并查看这些示例(按一列分组),然后将其应用于按多列分组的数据即可。 有关此处使用的不同方法和对象的更多信息,请参见Pandas文档

    结论: (Conclusion:)

    In this Pandas groupby tutorial we have learned how to use Pandas groupby to:

    在此Pandas groupby教程中,我们学习了如何使用Pandas groupby进行以下操作:

    • group one or many columns
    • count observations using the methods count and size
    • calculate simple summary statistics using:
      • groupby mean, median, std
      • groupby agg (aggregate)
      • agg with our own function
    • Calculate the percentage of observations in different groups
    • 分组一列或多列
    • 使用计数和大小方法计数观察值
    • 使用以下方法计算简单的摘要统计信息:
      • groupby平均值,中位数,标准
      • groupby agg(汇总)
      • 用我们自己的功能
    • 计算不同组中观察值的百分比

    翻译自: https://www.pybloggers.com/2018/12/python-pandas-groupby-tutorial/

    展开全文
  • MySQL查询优化:GROUP BY

    万次阅读 多人点赞 2019-03-05 19:46:16
    一、group by group by 优化方法 — 索引 松散索引扫描(Loose Index Scan) 为什么松散索引扫描的效率会很高? 紧凑索引扫描(Tight Index Scan) group by 优化方法 — 直接排序 二、group by 与 distinct ...

    目录

    一、group by

    group by 优化方法 — 索引

    松散索引扫描(Loose Index Scan)

    为什么松散索引扫描的效率会很高?

    紧凑索引扫描(Tight Index Scan)

    group by 优化方法 — 直接排序

    二、group by 与 distinct

    三、排序不一致问题


    一、group by

    当我们执行 group by 操作在没有合适的索引可用的时候,通常先扫描整个表提取数据并创建一个临时表,然后按照 group by 指定的列进行排序。在这个临时表里面,对于每一个 group 的数据行来说是连续在一起的。完成排序之后,就可以发现所有的 groups,并可以执行聚集函数(aggregate function)。可以看到,在没有使用索引的时候,需要创建临时表和排序。在执行计划中通常可以看到“Using temporary; Using filesort”。

     

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    create table t1(id int primary key, a int, b int, index(a));

    delimiter ;;

    create procedure idata()

    begin

      declare i int;

     

      set i=1;

      while(i<=1000)do

        insert into t1 values(i, i, i);

        set i=i+1;

      end while;

    end;;

    delimiter ;

    call idata();

    一个常见的使用临时表的例子是 group by,我们来看一下这个语句:

    1

    select id%10 as m, count(*) as c from t1 group by m;

    这个语句的逻辑是把表 t1 里的数据,按照 id%10 进行分组统计,并按照 m 的结果排序后输出。它的 explain 结果如下:

     

    1

    2

    3

    4

    5

    6

    7

    mysql> explain select id%10 as m, count(*) as c from t1 group by m;

    +----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+----------------------------------------------+

    | id | select_type | table | partitions | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                        |

    +----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+----------------------------------------------+

    |  1 | SIMPLE      | t1    | NULL       | index | PRIMARY,a     | a    | 5       | NULL | 1000 |   100.00 | Using index; Using temporary; Using filesort |

    +----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+----------------------------------------------+

    1 row in set, 1 warning (0.01 sec)

    在 Extra 字段里面,我们可以看到三个信息:

    • Using index,表示这个语句使用了覆盖索引,选择了索引 a,不需要回表;
    • Using temporary,表示使用了临时表;
    • Using filesort,表示需要排序。

    这个语句的执行流程是这样的:

    1. 创建内存临时表,表里有两个字段 m 和 c,主键是 m;

    2. 扫描表 t1 的索引 a,依次取出叶子节点上的 id 值,计算 id%10 的结果,记为 x;

    3. 如果临时表中没有主键为 x 的行,就插入一个记录 (x,1); 如果表中有主键为 x 的行,就将 x 这一行的 c 值加 1;

    4. 遍历完成后,再根据字段 m 做排序,得到结果集返回给客户端。

    这个流程的流程图如下:

     

    接下来,我们再看一下这条语句的执行结果:

     

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    mysql> select id%10 as m, count(*) as c from t1 group by m;

    +------+-----+

    | m    | c   |

    +------+-----+

    |    0 | 100 |

    |    1 | 100 |

    |    2 | 100 |

    |    3 | 100 |

    |    4 | 100 |

    |    5 | 100 |

    |    6 | 100 |

    |    7 | 100 |

    |    8 | 100 |

    |    9 | 100 |

    +------+-----+

    10 rows in set (0.01 sec)

    如果你的需求并不需要对结果进行排序,那你可以在 SQL 语句末尾增加 order by null,也就是改成:

     

    1

    select id%10 as m, count(*) as c from t1 group by m order by null;

    这样就跳过了最后排序的阶段,直接从临时表中取数据返回。返回结果如下:

     

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    mysql> select id%10 as m, count(*) as c from t1 group by m order by null;

    +------+-----+

    | m    | c   |

    +------+-----+

    |    1 | 100 |

    |    2 | 100 |

    |    3 | 100 |

    |    4 | 100 |

    |    5 | 100 |

    |    6 | 100 |

    |    7 | 100 |

    |    8 | 100 |

    |    9 | 100 |

    |    0 | 100 |

    +------+-----+

    10 rows in set (0.00 sec)

    由于表 t1 中的 id 值是从 1 开始的,因此返回的结果集中第一行是 id=1;扫描到 id=10 的时候才插入 m=0 这一行,因此结果集里最后一行才是 m=0。

    这个例子里由于临时表只有 10 行,内存可以放得下,因此全程只使用了内存临时表。但是,内存临时表的大小是有限制的,参数 tmp_table_size 就是控制这个内存大小的,默认是 16M。

    如果我执行下面这个语句序列:

     

    1

    2

    set tmp_table_size=1024;

    select id%100 as m, count(*) as c from t1 group by m order by null limit 10;

    把内存临时表的大小限制为最大 1024 字节,并把语句改成 id % 100,这样返回结果里有 100 行数据。但是,这时的内存临时表大小不够存下这 100 行数据,也就是说,执行过程中会发现内存临时表大小到达了上限(1024 字节)。

    那么,当内存放不下时,这时候就会把内存临时表转成磁盘临时表,磁盘临时表默认使用的引擎是 InnoDB。这时,返回结果如下:

     

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    mysql> select id%100 as m, count(*) as c from t1 group by m order by null limit 10;

    +------+----+

    | m    | c  |

    +------+----+

    |    0 | 10 |

    |    1 | 10 |

    |    2 | 10 |

    |    3 | 10 |

    |    4 | 10 |

    |    5 | 10 |

    |    6 | 10 |

    |    7 | 10 |

    |    8 | 10 |

    |    9 | 10 |

    +------+----+

    10 rows in set (0.01 sec)

    如果这个表 t1 的数据量很大,很可能这个查询需要的磁盘临时表就会占用大量的磁盘空间。

    可以看出,相同的语句,由于调整 tmp_table_size 参数大小,查询结果排序方式却不同。这就是因为第一个查询使用的是内存临时表,上面已经提到了,是按照表 t1 的索引 a 顺序取出数据,模 10 得 0 的 id 是最后一行;第二个查询使用的是硬盘临时表,默认用 InnoDB 的引擎,主键是 id%10,因此存入硬盘后再按主键树顺序取出,0 就排到第一行了,InnoDB 表是顺序存储的。

    group by 优化方法 — 索引

    可以看到,不论是使用内存临时表还是磁盘临时表,group by 逻辑都需要构造一个带唯一索引的表,执行代价都是比较高的。如果表的数据量比较大,上面这个 group by 语句执行起来就会很慢,我们有什么优化的方法呢?

    要解决 group by 语句的优化问题,你可以先想一下这个问题:执行 group by 语句为什么需要临时表? group by 的语义逻辑,是统计不同的值出现的个数。但是,由于每一行的 id%100 的结果是无序的,所以我们就需要有一个临时表,来记录并统计结果。 那么,如果扫描过程中可以保证出现的数据是有序的,是不是就简单了呢?

    确实是这样,如果可以确保输入的数据是有序的,那么计算 group by 的时候,就只需要从左到右,顺序扫描,依次累加。比如数据结构(0, 0, 1, 1, 2, 2),那么这个过程如下:

    • 当碰到第一个 1 的时候,已经知道累积了 X 个 0,结果集里的第一行就是 (0,X);
    • 当碰到第一个 2 的时候,已经知道累积了 Y 个 1,结果集里的第二行就是 (1,Y);

    按照这个逻辑执行的话,扫描到整个输入的数据结束,就可以拿到 group by 的结果,不需要临时表,也不需要再额外排序。也就是说,如果语句执行过程可以一边读数据,一边直接得到结果,是不需要额外内存的,否则就需要额外的内存,来保存中间结果。

    所以,我们自然想到索引。MySQL 建立的 B+Tree 索引原生就是有序的,如果通过读取索引就完成 group by 操作,那么就可避免创建临时表和排序。因此使用索引进行 group by 的最重要的前提条件是所有 group by 的参照列(分组依据的列)来自于同一个索引,且索引按照顺序存储所有的 key(即BTREE index,而HASH index没有顺序的概念)。

    MySQL 有两种索引扫描方式完成 group by 操作,分别是松散索引扫描和紧凑索引扫描以及临时表实现 group by。在松散索引扫描方式下,分组操作和范围预测(如果有的话)一起执行完成的。在紧凑索引扫描方式下,先对索引执行范围扫描(range scan),再对结果元组进行分组。

    松散索引扫描(Loose Index Scan)

    何谓松散索引扫描实现 group by 呢?实际上就是当 MySQL 利用索引扫描来实现 group by 的时候,并不需要扫描所有满足条件的索引键即可完成操作得出结果。

    松散索引扫描仅考虑索引中的一部分,当查询中没有 where 条件的时候,松散索引扫描读取的索引元组的个数和 groups 的数量相同,如果 where 条件包含范围查询,松散索引扫描查找每个 group 中第一个满足范围条件的键,并再次读取尽可能少的键。松散索引扫描只需要读取很少量的数据就可以完成 group by 操作,因而执行效率非常高。

    使用松散索引扫描需要满足以下条件:

    1. 查询在单一表上。

    2. group by 指定的所有列是索引的一个最左前缀,并且没有其它的列。比如表 t1(c1,c2,c3,c4)上建立了索引 (c1,c2,c3)。如果查询包含 “group by c1,c2”,那么可以使用松散索引扫描。但是 “group by c2,c3” (不是索引最左前缀) 和 “group by c1,c2,c4” (c4字段不在索引中)无法使用。

    3. 如果在选择列表 select list 中存在聚集函数,只能使用 min() 和 max() 两个聚集函数,并且指定的是同一列(如果 min() 和 max() 同时存在),这一列必须在索引中,且紧跟着 group by 指定的列。比如 select t1,t2,min(t3),max(t3) from t1 group by c1,c2。这源于索引的有序排序,优化器意识到 min/max 位于最左/右块,从而避免范围扫描。

    4. 如果查询中存在除了 group by 指定的列之外的索引其他部分,那么必须以常量的形式出现(除了min() 和 max() 两个聚集函数)。比如 select c1,c3 from t1 group by c1,c2 不能使用松散索引扫描。而 select c1,c3 from t1 where c3 = 3 group by c1,c2 可以使用松散索引扫描。

    5. 索引中的列必须索引整个数据列的值,而不是一个前缀索引。比如,c1 varchar(20), INDEX (c1(10)),这个索引没发用作松散索引扫描。

    如果查询能够使用松散索引扫描,那么执行计划中 Extra 中提示 “using index for group-by”。

    假设 t1(c1,c2,c3,c4) 表上有一个索引 idx(c1,c2,c3),松散索引扫描访问方法可用于以下查询:

     

    1

    2

    3

    4

    5

    6

    7

    SELECT c1, c2 FROM t1 GROUP BY c1, c2;

    SELECT DISTINCT c1, c2 FROM t1;

    SELECT c1, MIN(c2) FROM t1 GROUP BY c1;

    SELECT c1, c2 FROM t1 WHERE c1 < const GROUP BY c1, c2;

    SELECT MAX(c3), MIN(c3), c1, c2 FROM t1 WHERE c2 > const GROUP BY c1, c2;

    SELECT c2 FROM t1 WHERE c1 < const GROUP BY c1, c2;

    SELECT c1, c2 FROM t1 WHERE c3 = const GROUP BY c1, c2;

    执行以下查询无法使用松散索引扫描:

    • 除了 MIN() 或 MAX() 之外还有聚合功能,比如 SUM() :

     

     

    1

    SELECT c1, SUM(c2) FROM t1 GROUP BY c1;

     

    • group by 子句中的列不会形成索引的最左前缀:

     

     

    1

    SELECT c1, c2 FROM t1 GROUP BY c2, c3;

     

    • 查询列与 group by 不相等:

     

     

    1

    SELECT c1, c3 FROM t1 GROUP BY c1, c2;

    要查询包含 where c3=const 可以使用松散索引扫描。

    除了已经支持的 MIN() 和 MAX() 引用之外,松散索引扫描访问方法可以应用于选择列表中的其他形式的聚合函数引用,如:AVG(DISTINCT),SUM(DISTINCT)、COUNT(DISTINCT)。AVG(DISTINCT) 和 SUM(DISTINCT) 采取单个列参数,COUNT(DISTINCT) 可以有多个列参数。

    假设 t1(c1,c2,c3,c4) 表上有一个索引 idx(c1,c2,c3),松散索引扫描访问方法可用于以下查询:

     

    1

    2

    SELECT COUNT(DISTINCT c1), SUM(DISTINCT c1) FROM t1;

    SELECT COUNT(DISTINCT c1, c2), COUNT(DISTINCT c2, c1) FROM t1;

    为什么松散索引扫描的效率会很高?

    因为在没有 where 子句,也就是必须经过全索引扫描的时候,松散索引扫描需要读取的键值数量与分组的组数量一样多,也就是说比实际存在的键值数目要少很多。而在 where 子句包含范围判断式或者等值表达式的时候, 松散索引扫描查找满足范围条件的每个组的第1个关键字,并且再次读取尽可能最少数量的关键字。

    紧凑索引扫描(Tight Index Scan)

    group by 在无法使用松散索引扫描时,还可以选择紧凑索引扫描,若两者都不可选,则只能借助临时表。

    紧密索引扫描可以是完整索引扫描,也可以是范围索引扫描,具体取决于查询条件。

    如果 where 条件有范围扫描,那么紧凑索引扫描仅读取满足这些条件的键(索引元组),否则执行全索引扫描。这种方式读取所有 where 条件定义的范围内的键,或者扫描整个索引,因而称作紧凑索引扫描。对于紧凑索引扫描,只有在所有满足范围条件的键被找到之后才会执行分组操作。

    要使紧凑索引扫描起作用,在查询中存在常量相等的 where 条件字段(索引中的字段),且该字段在 group by 指定的字段的前面或者中间,来自于相等条件的常量能够填充搜索键中的间隙,因而可以构成一个索引的完整前缀,索引前缀能够用于索引查找。而如果需要排序 group by 结果,并且能够形成索引前缀的搜索关键字,还可以避免额外的排序操作,因为使用有顺序的索引的前缀进行搜索已经按顺序检索到了所有关键字。

    紧凑索引扫描实现 group by 和松散索引扫描的区别主要在于他需要在扫描索引的时候,读取所有满足条件的索引键,然后再根据读取的数据来完成 group by 操作得到相应结果。

    这时候的执行计划的 Extra 信息中已经没有 “Using index for group-by” 了,但并不是说 MySQL 的 group by 操作并不是通过索引完成的,只不过是需要访问 where 条件所限定的所有索引键信息之后才能得出结果。这就是通过紧凑索引扫描来实现 group by 的执行计划输出信息。

    假设 t1(c1,c2,c3,c4) 表上有一个索引 idx(c1,c2,c3),以下查询不适用于之前描述的松散索引扫描访问方法,但仍然可以使用紧凑索引扫描访问方法。

    • 这 group by 有一个间隙,但它被覆盖的条件为 c2 = ‘a’:

     

     

    1

    SELECT c1, c2, c3 FROM t1 WHERE c2 = 'a' GROUP BY c1, c3;

     

    • 这 group by 不是从列的第一部分开始,但是有一个条件为该部分提供了一个常数:

     

     

    1

    SELECT c1, c2, c3 FROM t1 WHERE c1 = 'a' GROUP BY c2, c3;

    在 MySQL 中,MySQL Query Optimizer 首先会选择尝试通过松散索引扫描来实现 group by 操作,当发现某些情况无法满足松散索引扫描实现 group by 的要求之后,才会尝试通过紧凑索引扫描来实现。

    当 group by 条件字段并不连续或者不是索引前缀部分的时候,MySQL Query Optimize 无法使用松散索引扫描,设置无法直接通过索引完成 group by 操作,因为缺失的索引键信息无法得到。但是,如果查询语句中存在一个常量值来引用缺失的索引键,则可以使用紧凑索引扫描完成 group by 操作,因为常量填充了搜索关键字中的“间隙”,可以形成完整的索引前缀,这些索引前缀可以用于索引查找。而如果需要排序 group by 结果,并且能够形成索引前缀的搜索关键字,MySQL 还可以避免额外的排序操作,因为使用有顺序的索引的前缀进行搜索已经按顺序检索到了所有关键字。

    group by 优化方法 — 直接排序

    如果我们明明知道,一个 group by 语句中需要放到临时表上的数据量特别大,却还是要按照“先放到内存临时表,插入一部分数据后,发现内存临时表不够用了再转成磁盘临时表”,看上去就有点儿傻。

    在 group by 语句中加入 SQL_BIG_RESULT 这个提示(hint),就可以告诉优化器:这个语句涉及的数据量很大,请直接用磁盘临时表。

    MySQL 的优化器一看,磁盘临时表是 B+ 树存储,存储效率不如数组来得高。所以,既然你告诉我数据量很大,那从磁盘空间考虑,还是直接用数组来存吧。

    因此,下面这个语句

     

    1

    select SQL_BIG_RESULT id%100 as m, count(*) as c from t1 group by m;

    的执行流程就是这样的:

    1. 初始化 sort_buffer,确定放入一个整型字段,记为 m;

    2. 扫描表 t1 的索引 a,依次取出里面的 id 值, 将 id%100 的值存入 sort_buffer 中;

    3. 扫描完成后,对 sort_buffer 的字段 m 做排序(如果 sort_buffer 内存不够用,就会利用磁盘临时文件辅助排序);

    4. 排序完成后,就得到了一个有序数组。

    根据有序数组,得到数组里面的不同值,以及每个值的出现次数。这一步的逻辑,已经从前面了解过了。执行流程如下图。

     

    1

    2

    3

    4

    5

    6

    7

    mysql> desc select SQL_BIG_RESULT id%100 as m, count(*) as c from t1 group by m;

    +----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-----------------------------+

    | id | select_type | table | partitions | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra                       |

    +----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-----------------------------+

    |  1 | SIMPLE      | t1    | NULL       | index | PRIMARY,a     | a    | 5       | NULL | 1000 |   100.00 | Using index; Using filesort |

    +----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-----------------------------+

    1 row in set, 1 warning (0.01 sec)

    从执行计划上来看,从 Extra 字段可以看到,这个语句的执行没有再使用临时表,而是直接用了排序算法,认为用 sort_buffer 直接排序性能更好。

    以上就介绍了MySQL查询优化MySQL分组查询Group By实现原理详解,包括了MySQL查询优化方面的内容,希望对MySQL有兴趣的朋友有所帮助。

    二、group by 与 distinct

    上面讲完 group by 的原理之后,还有一种与去重的语句 distinct。如果我们不需要对分组做聚合操作,那么 group by 与 distinct 谁的性能更好呢?

    如果表 t 的字段 a 上没有索引,那么下面这两条语句的性能是不是相同的:

     

    1

    2

    select a from t group by a order by null;

    select distinct a from t;

    首先需要说明的是,这种 group by 的写法,并不是 SQL 标准的写法。标准的 group by 语句,是需要在 select 部分加一个聚合函数,比如:

     

    1

    select a,count(*) from t group by a order by null;

    这条语句的逻辑是:按照字段 a 分组,计算每组的 a 出现的次数。在这个结果里,由于做的是聚合计算,相同的 a 只出现一次。

    没有了 count(*) 以后,也就是不再需要执行“计算总数”的逻辑时,第一条语句的逻辑就变成是:按照字段 a 做分组,相同的 a 的值只返回一行。而这就是 distinct 的语义,所以不需要执行聚合函数时,distinct 和 group by 这两条语句的语义和执行流程是相同的,因此执行性能也相同。

    这两条语句的执行流程是下面这样的。

    1. 创建一个临时表,临时表有一个字段 a,并且在这个字段 a 上创建一个唯一索引;

    2. 遍历表 t,依次取数据插入临时表中:如果发现唯一键冲突,就跳过;否则插入成功;

    3. 遍历完成后,将临时表作为结果集返回给客户端。

    三、排序不一致问题

    源起,阿里云论坛有人反应 MySQL 5.6 分页有重复值(排序字段没有用索引,或则直接是全表扫描),MariaDB 已经是优化后的方案,和 5.6 一致。阿里数据库月报也对此进行了回复:MySQL · 答疑解惑 · MySQL Sort 分页

    测试表和数据:

     

    1

    2

    3

    4

    5

    6

    7

    8

    create table t1(id int primary key, c1 int, c2 varchar(128));

    insert into t1 values(1,1,'a');

    insert into t1 values(2,2,'b');

    insert into t1 values(3,2,'c');

    insert into t1 values(4,2,'d');

    insert into t1 values(5,3,'e');

    insert into t1 values(6,4,'f');

    insert into t1 values(7,5,'g');

    假设每页 3 条记录,第一页 limit 0,3 和第二页 limit 3,3 查询结果如下:

     

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    # MySQL 5.6;

    mysql> select * from t1 order by c1 limit 0,3;

    +----+------+------+

    | id | c1   | c2   |

    +----+------+------+

    |  1 |    1 | a    |

    |  3 |    2 | c    |

    |  4 |    2 | d    |

    +----+------+------+

    3 rows in set (0.00 sec)

     

    mysql> select * from t1 order by c1 limit 3,3;

    +----+------+------+

    | id | c1   | c2   |

    +----+------+------+

    |  4 |    2 | d    |

    |  5 |    3 | e    |

    |  6 |    4 | f    |

    +----+------+------+

    3 rows in set (0.01 sec)

    我们可以看到 id 为 4 的这条记录居然同时出现在两次查询中,这明显是不符合预期的,而且在 5.5 版本中没有这个问题。

    使用优先队列排序的目的就是在不能使用索引有序性的时候,如果要排序,并且使用了 limit n,那么只需要在排序的过程中,保留 n 条记录即可,这样虽然不能解决所有记录都需要排序的开销,但是只需要 sort buffer 少量的内存就可以完成排序,上面已经说明。之所以 MySQL 5.6 出现了第二页数据重复的问题,是因为使用了优先队列排序,其使用了堆排序的排序方法,而堆排序是一个不稳定的排序方法,也就是相同的值(例子中的值2)可能排序出来的数据和读出来的数据顺序不一致,无法保证排序前后数据位置的一致,所以导致分页重复的现象。

    避免这个问题在阿里月报有说:MySQL · 答疑解惑 · MySQL Sort 分页

    但在 MySQL 5.7 版本中此问题又没有了。

     

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    # MySQL 5.7

    mysql> select * from t1 order by c1 limit 0,3;

    +----+------+------+

    | id | c1   | c2   |

    +----+------+------+

    |  1 |    1 | a    |

    |  2 |    2 | b    |

    |  3 |    2 | c    |

    +----+------+------+

    3 rows in set (0.00 sec)

     

    mysql> select * from t1 order by c1 limit 3,3;

    +----+------+------+

    | id | c1   | c2   |

    +----+------+------+

    |  4 |    2 | d    |

    |  5 |    3 | e    |

    |  6 |    4 | f    |

    +----+------+------+

    3 rows in set (0.00 sec)

    <参考>

    极客时间《MySQL 45讲实战》

    http://www.codes51.com/article/detail_1774816_1.html

    http://mysql.taobao.org/monthly/2015/06/04

    https://dev.mysql.com/doc/refman/5.7/en/group-by-optimization.html

    转载自:http://www.ywnds.com/?p=10174

    展开全文
  • pandas groupby 用法详解

    万次阅读 多人点赞 2020-12-21 22:55:56
    1.分组groupby 在日常数据分析过程中,经常有分组的需求。具体来说,就是根据一个或者多个字段,将数据划分为不同的组,然后进行进一步分析,比如求分组的数量,分组内的最大值最小值平均值等。在sql中,就是...

    项目github地址:bitcarmanlee easy-algorithm-interview-and-practice
    欢迎大家star,留言,一起学习进步

    1.分组groupby

    在日常数据分析过程中,经常有分组的需求。具体来说,就是根据一个或者多个字段,将数据划分为不同的组,然后进行进一步分析,比如求分组的数量,分组内的最大值最小值平均值等。在sql中,就是大名鼎鼎的groupby操作。
    pandas中,也有对应的groupby操作,下面我们就来看看pandas中的groupby怎么使用。

    2.groupby的数据结构

    首先我们看如下代码

    def ddd():
        levels = ["L1", "L1", "L1", "L2", "L2", "L3", "L3"]
        nums = [10, 20, 30, 20, 15, 10, 12]
        df = pd.DataFrame({"level": levels, "num": nums})
        g = df.groupby('level')
        print(g)
        print()
        print(list(g))
    

    输出结果如下:

    <pandas.core.groupby.generic.DataFrameGroupBy object at 0x10f6f96d0>
    
    [('L1',   level  num
    0    L1   10
    1    L1   20
    2    L1   30), ('L2',   level  num
    3    L2   20
    4    L2   15), ('L3',   level  num
    5    L3   10
    6    L3   12)]
    

    做groupby操作以后,得到的是一个DataFrameGroupBy对象,直接打印该对象的话,显示的是其内存地址。
    为了方便地观察数据,我们使用list方法转换一下,发现其是一个元组,元组中的第一个元素,是level的值。元祖中的第二个元素,则是其组别下的整个dataframe。

    3.groupby的基本用法

    def group1():
        levels = ["L1", "L1", "L1", "L2", "L2", "L3", "L3"]
        nums = [10, 20, 30, 20, 15, 10, 12]
        scores = [100, 200, 300, 200, 150, 100, 120]
        df = pd.DataFrame({"level": levels, "num": nums, "score": scores})
        result = df.groupby('level').agg({'num': 'sum', 'score': 'mean'})
        allnum = result['num'].sum()
        result['rate'] = result['num'].map(lambda x: x / allnum)
        print(result)
    

    最后输出:

           num  score      rate
    level                      
    L1      60    200  0.512821
    L2      35    175  0.299145
    L3      22    110  0.188034
    

    上面的例子展示了groupby的基本用法。
    对dataframe按照level分组,然后对num列求和,对score列求平均值,可以得到result。
    同时,我们还希望得到每个分组中,num的和在所有num和中的占比。于是我们先求num的综合,然后在用map方法,给result添加一列,求得其占比!

    4.transform的用法

    下面我们看一个更复杂的例子。

    def t10():
        levels = ["L1", "L1", "L1", "L2", "L2", "L3", "L3"]
        nums = [10, 20, 30, 20, 15, 10, 12]
        df = pd.DataFrame({"level": levels, "num": nums})
        ret = df.groupby('level')['num'].mean().to_dict()
        df['avg_num'] = df['level'].map(ret)
        print(ret)
        print(df)
    
    {'L1': 20.0, 'L2': 17.5, 'L3': 11.0}
      level  num  avg_num
    0    L1   10     20.0
    1    L1   20     20.0
    2    L1   30     20.0
    3    L2   20     17.5
    4    L2   15     17.5
    5    L3   10     11.0
    6    L3   12     11.0
    

    上面的方法,我们对level分组以后,我们想给数据集添加一列,想给每行数据添加每个level对应的平均值。
    上面的解法是先求得每个分组的平均值,转成一个dict,然后再使用map方法将每组的平均值添加上去。

    def trans():
        levels = ["L1", "L1", "L1", "L2", "L2", "L3", "L3"]
        nums = [10, 20, 30, 20, 15, 10, 12]
        df = pd.DataFrame({"level": levels, "num": nums})
        df['avg_num'] = df.groupby('level')['num'].transform('mean')
        print(df)
    

    如果使用transform方法,代码可以更简单更直观,如上所示。

    transform方法的作用:调用函数在每个分组上产生一个与原df相同索引的dataFrame,整体返回与原来对象拥有相同索引且已填充了转换后的值的dataFrame,相当于就是给原来的dataframe添加了一列。

    展开全文
  • 分组原理(GROUP BY子句)1:GROUP BY子句基本语法规则 若觉得本文写得还可以,请多多关注本人所作书籍《C++语法详解》电子工业出版社出版,作者 黄勇 本文为原创文章,转载请注明出处,或注明转载自“黄邦勇帅(原名:...
  • pandas之分组groupby()的使用整理与总结

    万次阅读 多人点赞 2019-07-27 18:41:53
    前言 在使用pandas的时候,有些场景需要对数据内部进行分组处理,如一组全校学生成绩的数据,我们想通过班级进行分组,或者再对班级分组后...groupby的作用可以参考 超好用的 pandas 之 groupby 中作者的插图进行直...
  • 【MySQL数据库】group by详解

    千次阅读 多人点赞 2019-07-03 12:29:18
    SELECT FROM WHERE GROUP BY HAVING ORDER BY LIMIT 先过滤行,然后分组,筛选组,对剩余组排序,选取指定的组集合。 记住:一旦分组完成,我们的后续操作都是对分组得到的虚拟表进行操作。 GROUP BY子句中列出来...
  • MySQL 根据日期 group by

    千次阅读 2020-12-15 14:45:02
    mysql 有一张这样的表,需要根据customer_ip_date这个字段的日期进行group by 排序,得出每天的数量是多少 MySQL 根据日期 group by有两种写法: 1.字符串截取:substring,从第一个字段截取到第十个字符串,然后...
  • group by 和 order by 的区别 + 理解过程

    万次阅读 多人点赞 2018-07-25 12:04:16
    order bygroup by 的区别 order by 和 group by 的区别: 1,order by 从英文里理解就是行的排序方式,默认的为升序。 order by 后面必须列出排序的字段名,可以是多个字段名。 2,group by 从...
  • pandas分组统计 - groupby功能

    万次阅读 多人点赞 2019-01-05 11:11:16
    分组统计 - groupby功能 ① 根据某些条件将数据拆分成组 ② 对每个组独立应用函数 ③ 将结果合并到一个数据结构中 Dataframe在行(axis=0)或列(axis=1)上进行分组,将一个函数应用到各个分组并产生一个新值,然后...
  • I have a data frame df and I use several columns from it to groupby : 我有一个数据框df ,我从中使用了几列到groupby
  • GROUP BY和HAVING用法介绍

    千次阅读 2020-09-09 16:00:26
    2、having必须和groupby一起用,且在groupby后面 3、groupby、having、order by的使用顺序:groupby 、having、order by SELECT *|字段列表 [as 别名] FROM 表名 [WHERE 子句] [GROUP BY 子句][HAVING 子句]...
  • Python-Groupby函数应用

    千次阅读 2018-11-17 20:32:49
    Pandas分组和聚合运算–Groupby函数应用 一、groupby函数功能 根据一个或多个键拆分pandas对象,计算分组摘要统计,如计数、平均值、标准差或用户自定义函数等。 二、groupby函数原理 可将groupby函数分组聚合的过程...
  • Mysql GROUP BY 排除null数据

    万次阅读 2021-02-25 15:40:04
    在使用group by某列名进行分组统计时,该列名的数据有些为 null, 因而会出现 null 的数据行全部分成一组导致数据错误,所以 null 列名的数据行不能执行group by 直接执行查询得到的结果为: 使用group by进行...
  • Group by函数

    千次阅读 2020-03-20 21:48:39
    Group by函数 1.前言 在数据库操作中分组操作经常用到。本文就来聊一聊,数据库中分组函数GROUP BY ; 2.创建测试表 示例表 CREATE TABLE `group_by_test` ( `id` INT ( 10 ) NOT NULL AUTO_INCREMENT COMMENT '...
  • SQL中GROUP BY语句介绍

    万次阅读 多人点赞 2018-12-27 10:21:16
    本文主要介绍 SQL(Structured Query Language)中 GROUP BY 语句的相关知识,同时通过用法示例介绍 GROUP BY 语句的常见用法。 1 概述 GROUP BY 语句通常用于配合聚合函数(如 COUNT()、MAX() 等),根据一个或多...
  • Clickhouse GROUP BY 子句 Having 子句

    千次阅读 2020-07-09 09:27:26
    参考: https://clickhouse.tech/docs/en/sql-reference/statements/select/group-by/ https://clickhouse.tech/docs/en/sql-reference/statements/select/having/
  • MySQL--Group by分组与count计数(进阶)

    万次阅读 2019-09-27 21:09:01
    MySQL--Group by分组与count计数(进阶)1、Group by语法2、创建表格3、题目代码部分4、文末彩蛋      更多关于数据库知识请加关注哟~~。若需联系和想安装MySQL请加博主:   &...
  • sql语句中GROUP BY 和 HAVING的用法

    万次阅读 多人点赞 2018-08-09 10:46:55
    having字句可以让我们筛选成组后的各种数据,where字句在聚合前先筛选记录,也就是说作用在group by和having字句前。而 having子句在聚合后对组记录进行筛选。 SQL实例: 一、显示每个地区的总人口数和总面积. ...
  • group by详解

    万次阅读 多人点赞 2018-09-16 22:06:51
    group_by的意思是根据by对数据按照哪个字段进行分组,或者是哪几个字段进行分组。 二. 语法 select 字段 from 表名 where 条件 group by 字段 或者 select 字段 from 表名 group by 字段 having 过滤条件 ...
  • pandas——很全的groupby、agg,对表格数据分组与统计

    万次阅读 多人点赞 2018-12-26 21:10:23
    groupby功能:以一种自然的方式对数据集切片、切块、摘要等操作。 根据一个或多个键(可以是函数、数组、DataFrame列名)拆分pandas对象。 计算分组摘要统计,如,计数、平均值、标准差、或用户自定义函数。对...
  •   我们可以通过groupby方法来对Series或DataFrame对象实现分组操作,该方法会返回一个分组对象。但是,如果直接查看(输出)该对象,并不能看到任何的分组信息。 1)groupby()函数语法 ① 语法如下 group...
  • 分组统计 - groupby功能 ① 根据某些条件将数据拆分成组 ② 对每个组独立应用函数 ③ 将结果合并到一个数据结构中 Dataframe在行(axis=0)或列(axis=1)上进行分组,将一个函数应用到各个分组并产生一个新值,...
  • groupby常用操作

    千次阅读 2018-09-29 16:17:40
    pandas提供了一个灵活高效的groupby功能,它使你能以一种自然的方式对数据集进行切片、切块、摘要等操作。根据一个或多个键(可以是函数、数组或DataFrame列名)拆分pandas对象。计算分组摘要统计,如计数、平均值、...
  • python pandas.DataFrame.groupby()方法详解

    千次阅读 2019-10-21 12:08:20
    文章目录DataFrame.groupby()概览应用举例 以下内容参考自官方文档 详情应用参考文档 DataFrame.groupby()概览 DataFrame.groupby(self, by=None, axis=0, level=None, as_index=True, sort=True, group_keys=...
  • python中的groupby方法详解

    千次阅读 2018-12-31 11:11:14
    1.GroupBy Mechanics(groupby技术) 2.Data Aggregation(数据聚合) 3.Group-wise Operation and Transformation(分组级运算和转换) 4.Pivot Tables and Cross-Tabulation(透视表和交叉表) 本文是...
  • pandas的Groupby加速

    千次阅读 2019-02-14 22:05:52
    在平时的金融数据处理中,模型构建中,经常会用到pandas的groupby。之前的一篇文章中也讲述过groupby的作用: https://blog.csdn.net/qtlyx/article/details/80515077  但是,大家都知道,python有一个东西叫做...
  • Group by 分组详解

    万次阅读 多人点赞 2018-11-22 16:25:16
    先来看下表1,表名为test:   表1  执行如下SQL语句: 1 ... GROUP BY name ... 可是为了能够更好的理解“group by”多个列“和”聚合函数“的应用,我建议在思考的过程中,由表1到表2的过程中...
  • python3中的groupby函数用法

    千次阅读 2019-03-07 17:51:15
    1.GroupBy Mechanics(groupby技术) 2.Data Aggregation(数据聚合) 3.Group-wise Operation and Transformation(分组级运算和转换) 4.Pivot Tables and Cross-Tabulation(透视表和交叉表) 本文是...
  • MySQL对group by原理和理解

    万次阅读 多人点赞 2019-06-03 17:57:18
    写在前面的话:用了好久group by,今天早上一觉醒来,突然感觉group by好陌生,总有个筋别不过来,为什么不能够select * from Table group by id,为什么一定不能是*,而是某一个列或者某个列的聚合函数,group by ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 857,575
精华内容 343,030
关键字:

groupby