Pandas怎样对每个分组应用apply函数?

Pandas怎样对每个分组应用apply函数?

知识:Pandas的GroupBy遵从split、apply、combine模式

这里的split指的是pandas的groupby,我们自己实现apply函数,apply返回的结果由pandas进行combine得到结果

GroupBy.apply(function)

  • function的第一个参数是dataframe
  • function的返回结果,可是dataframe、series、单个值,甚至和输入dataframe完全没关系

本次实例演示:

  1. 怎样对数值列按分组的归一化?
  2. 怎样取每个分组的TOPN数据?

实例1:怎样对数值列按分组的归一化?

将不同范围的数值列进行归一化,映射到[0,1]区间:
* 更容易做数据横向对比,比如价格字段是几百到几千,增幅字段是0到100
* 机器学习模型学的更快性能更好

归一化的公式:

演示:用户对电影评分的归一化

每个用户的评分不同,有的乐观派评分高,有的悲观派评分低,按用户做归一化

import pandas as pd
ratings = pd.read_csv(
    "./datas/movielens-1m/ratings.dat", 
    sep="::",
    engine='python', 
    names="UserID::MovieID::Rating::Timestamp".split("::")
)
ratings.head()
UserIDMovieIDRatingTimestamp
0111935978300760
116613978302109
219143978301968
3134084978300275
4123555978824291
# 实现按照用户ID分组,然后对其中一列归一化
def ratings_norm(df):
    """
    @param df:每个用户分组的dataframe
    """
    min_value = df["Rating"].min()
    max_value = df["Rating"].max()
    df["Rating_norm"] = df["Rating"].apply(
        lambda x: (x-min_value)/(max_value-min_value))
    return df

ratings = ratings.groupby("UserID").apply(ratings_norm)
ratings[ratings["UserID"]==1].head()
UserIDMovieIDRatingTimestampRating_norm
01119359783007601.0
1166139783021090.0
2191439783019680.0
31340849783002750.5
41235559788242911.0

可以看到UserID==1这个用户,Rating==3是他的最低分,是个乐观派,我们归一化到0分;

实例2:怎样取每个分组的TOPN数据?

获取2018年每个月温度最高的2天数据

fpath = "./datas/beijing_tianqi/beijing_tianqi_2018.csv"
df = pd.read_csv(fpath)
# 替换掉温度的后缀℃
df.loc[:, "bWendu"] = df["bWendu"].str.replace("℃", "").astype('int32')
df.loc[:, "yWendu"] = df["yWendu"].str.replace("℃", "").astype('int32')
# 新增一列为月份
df['month'] = df['ymd'].str[:7]
df.head()
ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevelmonth
02018-01-013-6晴~多云东北风1-2级5922018-01
12018-01-022-5阴~多云东北风1-2级4912018-01
22018-01-032-5多云北风1-2级2812018-01
32018-01-040-8东北风1-2级2812018-01
42018-01-053-6多云~晴西北风1-2级5012018-01
def getWenduTopN(df, topn):
    """
    这里的df,是每个月份分组group的df
    """
    return df.sort_values(by="bWendu")[["ymd", "bWendu"]][-topn:]

df.groupby("month").apply(getWenduTopN, topn=1).head()
ymdbWendu
month
2018-01182018-01-197
2018-02562018-02-2612
2018-03852018-03-2727
2018-041182018-04-2930
2018-051502018-05-3135

我们看到,grouby的apply函数返回的dataframe,其实和原来的dataframe其实可以完全不一样

视频地址在:
http://www.iqiyi.com/a_19rrhyyqix.html

怎样使用Pandas的map和apply函数?

数据转换函数对比:map、apply、applymap:
1. map:只用于Series,实现每个值->值的映射;
2. apply:用于Series实现每个值的处理,用于Dataframe实现某个轴的Series的处理;
3. applymap:只能用于DataFrame,用于处理该DataFrame的每个元素;

1. map用于Series值的转换

实例:将股票代码英文转换成中文名字

Series.map(dict) or Series.map(function)均可

import pandas as pd
stocks = pd.read_excel('./datas/stocks/互联网公司股票.xlsx')
stocks.head()
日期公司收盘开盘交易量涨跌幅
02019-10-03BIDU104.32102.35104.73101.152.240.02
12019-10-02BIDU102.62100.85103.2499.502.690.01
22019-10-01BIDU102.00102.80103.26101.001.78-0.01
32019-10-03BABA169.48166.65170.18165.0010.390.02
42019-10-02BABA165.77162.82166.88161.9011.600.00
stocks["公司"].unique()
array(['BIDU', 'BABA', 'IQ', 'JD'], dtype=object)
# 公司股票代码到中文的映射,注意这里是小写
dict_company_names = {
    "bidu": "百度",
    "baba": "阿里巴巴",
    "iq": "爱奇艺", 
    "jd": "京东"
}

方法1:Series.map(dict)

stocks["公司中文1"] = stocks["公司"].str.lower().map(dict_company_names)
stocks.head()
日期公司收盘开盘交易量涨跌幅公司中文1
02019-10-03BIDU104.32102.35104.73101.152.240.02百度
12019-10-02BIDU102.62100.85103.2499.502.690.01百度
22019-10-01BIDU102.00102.80103.26101.001.78-0.01百度
32019-10-03BABA169.48166.65170.18165.0010.390.02阿里巴巴
42019-10-02BABA165.77162.82166.88161.9011.600.00阿里巴巴

方法2:Series.map(function)

function的参数是Series的每个元素的值

stocks["公司中文2"] = stocks["公司"].map(lambda x : dict_company_names[x.lower()])
stocks.head()
日期公司收盘开盘交易量涨跌幅公司中文1公司中文2
02019-10-03BIDU104.32102.35104.73101.152.240.02百度百度
12019-10-02BIDU102.62100.85103.2499.502.690.01百度百度
22019-10-01BIDU102.00102.80103.26101.001.78-0.01百度百度
32019-10-03BABA169.48166.65170.18165.0010.390.02阿里巴巴阿里巴巴
42019-10-02BABA165.77162.82166.88161.9011.600.00阿里巴巴阿里巴巴

2. apply用于Series和DataFrame的转换

  • Series.apply(function), 函数的参数是每个值
  • DataFrame.apply(function), 函数的参数是Series

Series.apply(function)

function的参数是Series的每个值

stocks["公司中文3"] = stocks["公司"].apply(
    lambda x : dict_company_names[x.lower()])
stocks.head()
日期公司收盘开盘交易量涨跌幅公司中文1公司中文2公司中文3
02019-10-03BIDU104.32102.35104.73101.152.240.02百度百度百度
12019-10-02BIDU102.62100.85103.2499.502.690.01百度百度百度
22019-10-01BIDU102.00102.80103.26101.001.78-0.01百度百度百度
32019-10-03BABA169.48166.65170.18165.0010.390.02阿里巴巴阿里巴巴阿里巴巴
42019-10-02BABA165.77162.82166.88161.9011.600.00阿里巴巴阿里巴巴阿里巴巴

DataFrame.apply(function)

function的参数是对应轴的Series

stocks["公司中文4"] = stocks.apply(
    lambda x : dict_company_names[x["公司"].lower()], 
    axis=1)

注意这个代码:
1、apply是在stocks这个DataFrame上调用;
2、lambda x的x是一个Series,因为指定了axis=1所以Seires的key是列名,可以用x[‘公司’]获取

stocks.head()
日期公司收盘开盘交易量涨跌幅公司中文1公司中文2公司中文3公司中文4
02019-10-03BIDU104.32102.35104.73101.152.240.02百度百度百度百度
12019-10-02BIDU102.62100.85103.2499.502.690.01百度百度百度百度
22019-10-01BIDU102.00102.80103.26101.001.78-0.01百度百度百度百度
32019-10-03BABA169.48166.65170.18165.0010.390.02阿里巴巴阿里巴巴阿里巴巴阿里巴巴
42019-10-02BABA165.77162.82166.88161.9011.600.00阿里巴巴阿里巴巴阿里巴巴阿里巴巴

3. applymap用于DataFrame所有值的转换

sub_df = stocks[['收盘', '开盘', '高', '低', '交易量']]
sub_df.head()
收盘开盘交易量
0104.32102.35104.73101.152.24
1102.62100.85103.2499.502.69
2102.00102.80103.26101.001.78
3169.48166.65170.18165.0010.39
4165.77162.82166.88161.9011.60
# 将这些数字取整数,应用于所有元素
sub_df.applymap(lambda x : int(x))
收盘开盘交易量
01041021041012
1102100103992
21021021031011
316916617016510
416516216616111
516516816816314
61615161510
7151515158
81516161511
9282828278
10282828279
112828282710
# 直接修改原df的这几列
stocks.loc[:, ['收盘', '开盘', '高', '低', '交易量']] = sub_df.applymap(lambda x : int(x))
stocks.head()
日期公司收盘开盘交易量涨跌幅公司中文1公司中文2公司中文3公司中文4
02019-10-03BIDU10410210410120.02百度百度百度百度
12019-10-02BIDU1021001039920.01百度百度百度百度
22019-10-01BIDU1021021031011-0.01百度百度百度百度
32019-10-03BABA169166170165100.02阿里巴巴阿里巴巴阿里巴巴阿里巴巴
42019-10-02BABA165162166161110.00阿里巴巴阿里巴巴阿里巴巴阿里巴巴

Pandas的分层索引MultiIndex怎样用?

Pandas的分层索引MultiIndex

为什么要学习分层索引MultiIndex?
* 分层索引:在一个轴向上拥有多个索引层级,可以表达更高维度数据的形式;
* 可以更方便的进行数据筛选,如果有序则性能更好;
* groupby等操作的结果,如果是多KEY,结果是分层索引,需要会使用
* 一般不需要自己创建分层索引(MultiIndex有构造函数但一般不用)

演示数据:百度、阿里巴巴、爱奇艺、京东四家公司的10天股票数据
数据来自:英为财经
https://cn.investing.com/

本次演示提纲:
一、Series的分层索引MultiIndex
二、Series有多层索引怎样筛选数据?
三、DataFrame的多层索引MultiIndex
四、DataFrame有多层索引怎样筛选数据?

import pandas as pd
%matplotlib inline
stocks = pd.read_excel('./datas/stocks/互联网公司股票.xlsx')
stocks.shape
(12, 8)
stocks.head(3)
日期公司收盘开盘交易量涨跌幅
02019-10-03BIDU104.32102.35104.73101.152.240.02
12019-10-02BIDU102.62100.85103.2499.502.690.01
22019-10-01BIDU102.00102.80103.26101.001.78-0.01
stocks["公司"].unique()
array(['BIDU', 'BABA', 'IQ', 'JD'], dtype=object)
stocks.index
RangeIndex(start=0, stop=12, step=1)
stocks.groupby('公司')["收盘"].mean()
公司
BABA    166.80
BIDU    102.98
IQ       15.90
JD       28.35
Name: 收盘, dtype: float64

一、Series的分层索引MultiIndex

ser = stocks.groupby(['公司', '日期'])['收盘'].mean()
ser
公司    日期        
BABA  2019-10-01    165.15
      2019-10-02    165.77
      2019-10-03    169.48
BIDU  2019-10-01    102.00
      2019-10-02    102.62
      2019-10-03    104.32
IQ    2019-10-01     15.92
      2019-10-02     15.72
      2019-10-03     16.06
JD    2019-10-01     28.19
      2019-10-02     28.06
      2019-10-03     28.80
Name: 收盘, dtype: float64

多维索引中,空白的意思是:使用上面的值

ser.index
MultiIndex([('BABA', '2019-10-01'),
            ('BABA', '2019-10-02'),
            ('BABA', '2019-10-03'),
            ('BIDU', '2019-10-01'),
            ('BIDU', '2019-10-02'),
            ('BIDU', '2019-10-03'),
            (  'IQ', '2019-10-01'),
            (  'IQ', '2019-10-02'),
            (  'IQ', '2019-10-03'),
            (  'JD', '2019-10-01'),
            (  'JD', '2019-10-02'),
            (  'JD', '2019-10-03')],
           names=['公司', '日期'])
# unstack把二级索引变成列
ser.unstack()
日期2019-10-012019-10-022019-10-03
公司
BABA165.15165.77169.48
BIDU102.00102.62104.32
IQ15.9215.7216.06
JD28.1928.0628.80
ser
公司    日期        
BABA  2019-10-01    165.15
      2019-10-02    165.77
      2019-10-03    169.48
BIDU  2019-10-01    102.00
      2019-10-02    102.62
      2019-10-03    104.32
IQ    2019-10-01     15.92
      2019-10-02     15.72
      2019-10-03     16.06
JD    2019-10-01     28.19
      2019-10-02     28.06
      2019-10-03     28.80
Name: 收盘, dtype: float64
ser.reset_index()
公司日期收盘
0BABA2019-10-01165.15
1BABA2019-10-02165.77
2BABA2019-10-03169.48
3BIDU2019-10-01102.00
4BIDU2019-10-02102.62
5BIDU2019-10-03104.32
6IQ2019-10-0115.92
7IQ2019-10-0215.72
8IQ2019-10-0316.06
9JD2019-10-0128.19
10JD2019-10-0228.06
11JD2019-10-0328.80

二、Series有多层索引MultiIndex怎样筛选数据?

ser
公司    日期        
BABA  2019-10-01    165.15
      2019-10-02    165.77
      2019-10-03    169.48
BIDU  2019-10-01    102.00
      2019-10-02    102.62
      2019-10-03    104.32
IQ    2019-10-01     15.92
      2019-10-02     15.72
      2019-10-03     16.06
JD    2019-10-01     28.19
      2019-10-02     28.06
      2019-10-03     28.80
Name: 收盘, dtype: float64
ser.loc['BIDU']
日期
2019-10-01    102.00
2019-10-02    102.62
2019-10-03    104.32
Name: 收盘, dtype: float64
# 多层索引,可以用元组的形式筛选
ser.loc[('BIDU', '2019-10-02')]
102.62
ser.loc[:, '2019-10-02']
公司
BABA    165.77
BIDU    102.62
IQ       15.72
JD       28.06
Name: 收盘, dtype: float64

三、DataFrame的多层索引MultiIndex

stocks.head()
日期公司收盘开盘交易量涨跌幅
02019-10-03BIDU104.32102.35104.73101.152.240.02
12019-10-02BIDU102.62100.85103.2499.502.690.01
22019-10-01BIDU102.00102.80103.26101.001.78-0.01
32019-10-03BABA169.48166.65170.18165.0010.390.02
42019-10-02BABA165.77162.82166.88161.9011.600.00
stocks.set_index(['公司', '日期'], inplace=True)
stocks
收盘开盘交易量涨跌幅
公司日期
BIDU2019-10-03104.32102.35104.73101.152.240.02
2019-10-02102.62100.85103.2499.502.690.01
2019-10-01102.00102.80103.26101.001.78-0.01
BABA2019-10-03169.48166.65170.18165.0010.390.02
2019-10-02165.77162.82166.88161.9011.600.00
2019-10-01165.15168.01168.23163.6414.19-0.01
IQ2019-10-0316.0615.7116.3815.3210.080.02
2019-10-0215.7215.8515.8715.128.10-0.01
2019-10-0115.9216.1416.2215.5011.65-0.01
JD2019-10-0328.8028.1128.9727.828.770.03
2019-10-0228.0628.0028.2227.539.530.00
2019-10-0128.1928.2228.5727.9710.640.00
stocks.index
MultiIndex([('BIDU', '2019-10-03'),
            ('BIDU', '2019-10-02'),
            ('BIDU', '2019-10-01'),
            ('BABA', '2019-10-03'),
            ('BABA', '2019-10-02'),
            ('BABA', '2019-10-01'),
            (  'IQ', '2019-10-03'),
            (  'IQ', '2019-10-02'),
            (  'IQ', '2019-10-01'),
            (  'JD', '2019-10-03'),
            (  'JD', '2019-10-02'),
            (  'JD', '2019-10-01')],
           names=['公司', '日期'])
stocks.sort_index(inplace=True)
stocks
收盘开盘交易量涨跌幅
公司日期
BABA2019-10-01165.15168.01168.23163.6414.19-0.01
2019-10-02165.77162.82166.88161.9011.600.00
2019-10-03169.48166.65170.18165.0010.390.02
BIDU2019-10-01102.00102.80103.26101.001.78-0.01
2019-10-02102.62100.85103.2499.502.690.01
2019-10-03104.32102.35104.73101.152.240.02
IQ2019-10-0115.9216.1416.2215.5011.65-0.01
2019-10-0215.7215.8515.8715.128.10-0.01
2019-10-0316.0615.7116.3815.3210.080.02
JD2019-10-0128.1928.2228.5727.9710.640.00
2019-10-0228.0628.0028.2227.539.530.00
2019-10-0328.8028.1128.9727.828.770.03

四、DataFrame有多层索引MultiIndex怎样筛选数据?

重要知识】在选择数据时:
* 元组(key1,key2)代表筛选多层索引,其中key1是索引第一级,key2是第二级,比如key1=JD, key2=2019-10-02
* 列表[key1,key2]代表同一层的多个KEY,其中key1和key2是并列的同级索引,比如key1=JD, key2=BIDU

stocks.loc['BIDU']
收盘开盘交易量涨跌幅
日期
2019-10-01102.00102.80103.26101.001.78-0.01
2019-10-02102.62100.85103.2499.502.690.01
2019-10-03104.32102.35104.73101.152.240.02
stocks.loc[('BIDU', '2019-10-02'), :]
收盘     102.62
开盘     100.85
高      103.24
低       99.50
交易量      2.69
涨跌幅      0.01
Name: (BIDU, 2019-10-02), dtype: float64
stocks.loc[('BIDU', '2019-10-02'), '开盘']
100.85
stocks.loc[['BIDU', 'JD'], :]
收盘开盘交易量涨跌幅
公司日期
BIDU2019-10-01102.00102.80103.26101.001.78-0.01
2019-10-02102.62100.85103.2499.502.690.01
2019-10-03104.32102.35104.73101.152.240.02
JD2019-10-0128.1928.2228.5727.9710.640.00
2019-10-0228.0628.0028.2227.539.530.00
2019-10-0328.8028.1128.9727.828.770.03
stocks.loc[(['BIDU', 'JD'], '2019-10-03'), :]
收盘开盘交易量涨跌幅
公司日期
BIDU2019-10-03104.32102.35104.73101.152.240.02
JD2019-10-0328.8028.1128.9727.828.770.03
stocks.loc[(['BIDU', 'JD'], '2019-10-03'), '收盘']
公司    日期        
BIDU  2019-10-03    104.32
JD    2019-10-03     28.80
Name: 收盘, dtype: float64
stocks.loc[('BIDU', ['2019-10-02', '2019-10-03']), '收盘']
公司    日期        
BIDU  2019-10-02    102.62
      2019-10-03    104.32
Name: 收盘, dtype: float64
# slice(None)代表筛选这一索引的所有内容
stocks.loc[(slice(None), ['2019-10-02', '2019-10-03']), :]
收盘开盘交易量涨跌幅
公司日期
BABA2019-10-02165.77162.82166.88161.9011.600.00
2019-10-03169.48166.65170.18165.0010.390.02
BIDU2019-10-02102.62100.85103.2499.502.690.01
2019-10-03104.32102.35104.73101.152.240.02
IQ2019-10-0215.7215.8515.8715.128.10-0.01
2019-10-0316.0615.7116.3815.3210.080.02
JD2019-10-0228.0628.0028.2227.539.530.00
2019-10-0328.8028.1128.9727.828.770.03
stocks.reset_index()
公司日期收盘开盘交易量涨跌幅
0BABA2019-10-01165.15168.01168.23163.6414.19-0.01
1BABA2019-10-02165.77162.82166.88161.9011.600.00
2BABA2019-10-03169.48166.65170.18165.0010.390.02
3BIDU2019-10-01102.00102.80103.26101.001.78-0.01
4BIDU2019-10-02102.62100.85103.2499.502.690.01
5BIDU2019-10-03104.32102.35104.73101.152.240.02
6IQ2019-10-0115.9216.1416.2215.5011.65-0.01
7IQ2019-10-0215.7215.8515.8715.128.10-0.01
8IQ2019-10-0316.0615.7116.3815.3210.080.02
9JD2019-10-0128.1928.2228.5727.9710.640.00
10JD2019-10-0228.0628.0028.2227.539.530.00
11JD2019-10-0328.8028.1128.9727.828.770.03

转载请注明链接: http://www.crazyant.net/2598.html

Pandas怎样实现对数据的分组统计?

Pandas怎样实现groupby分组统计

类似SQL:
select city,max(temperature) from city_weather group by city;

groupby:先对数据分组,然后在每个分组上应用聚合函数、转换函数

本次演示:
一、分组使用聚合函数做数据统计
二、遍历groupby的结果理解执行流程
三、实例分组探索天气数据

import pandas as pd
import numpy as np
# 加上这一句,能在jupyter notebook展示matplot图表
%matplotlib inline
df = pd.DataFrame({'A': ['foo', 'bar', 'foo', 'bar', 'foo', 'bar', 'foo', 'foo'],
                   'B': ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'],
                   'C': np.random.randn(8),
                   'D': np.random.randn(8)})
df
ABCD
0fooone0.5429030.788896
1barone-0.375789-0.345869
2footwo-0.9034070.428031
3barthree-1.5647480.081163
4footwo-1.0936020.837348
5bartwo-0.2024030.701301
6fooone-0.665189-1.505290
7foothree-0.4983390.534438

一、分组使用聚合函数做数据统计

1、单个列groupby,查询所有数据列的统计

df.groupby('A').sum()
CD
A
bar-2.1429400.436595
foo-2.6176331.083423

我们看到:
1. groupby中的’A’变成了数据的索引列
2. 因为要统计sum,但B列不是数字,所以被自动忽略掉

2、多个列groupby,查询所有数据列的统计

df.groupby(['A','B']).mean()
CD
AB
barone-0.375789-0.345869
three-1.5647480.081163
two-0.2024030.701301
fooone-0.061143-0.358197
three-0.4983390.534438
two-0.9985040.632690

我们看到:(‘A’,’B’)成对变成了二级索引

df.groupby(['A','B'], as_index=False).mean()
ABCD
0barone-0.375789-0.345869
1barthree-1.5647480.081163
2bartwo-0.2024030.701301
3fooone-0.061143-0.358197
4foothree-0.4983390.534438
5footwo-0.9985040.632690

3、同时查看多种数据统计

df.groupby('A').agg([np.sum, np.mean, np.std])
CD
summeanstdsummeanstd
A
bar-2.142940-0.7143130.7415830.4365950.1455320.526544
foo-2.617633-0.5235270.6378221.0834230.2166850.977686

我们看到:列变成了多级索引

4、查看单列的结果数据统计

# 方法1:预过滤,性能更好
df.groupby('A')['C'].agg([np.sum, np.mean, np.std])
summeanstd
A
bar-2.142940-0.7143130.741583
foo-2.617633-0.5235270.637822
# 方法2
df.groupby('A').agg([np.sum, np.mean, np.std])['C']
summeanstd
A
bar-2.142940-0.7143130.741583
foo-2.617633-0.5235270.637822

5、不同列使用不同的聚合函数

df.groupby('A').agg({"C":np.sum, "D":np.mean})
CD
A
bar-2.1429400.145532
foo-2.6176330.216685

二、遍历groupby的结果理解执行流程

for循环可以直接遍历每个group

1、遍历单个列聚合的分组
g = df.groupby('A')
g
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x00000123B250E548>
for name,group in g:
    print(name)
    print(group)
    print()
bar
     A      B         C         D
1  bar    one -0.375789 -0.345869
3  bar  three -1.564748  0.081163
5  bar    two -0.202403  0.701301

foo
     A      B         C         D
0  foo    one  0.542903  0.788896
2  foo    two -0.903407  0.428031
4  foo    two -1.093602  0.837348
6  foo    one -0.665189 -1.505290
7  foo  three -0.498339  0.534438

可以获取单个分组的数据

g.get_group('bar')
ABCD
1barone-0.375789-0.345869
3barthree-1.5647480.081163
5bartwo-0.2024030.701301
2、遍历多个列聚合的分组
g = df.groupby(['A', 'B'])
for name,group in g:
    print(name)
    print(group)
    print()
('bar', 'one')
     A    B         C         D
1  bar  one -0.375789 -0.345869

('bar', 'three')
     A      B         C         D
3  bar  three -1.564748  0.081163

('bar', 'two')
     A    B         C         D
5  bar  two -0.202403  0.701301

('foo', 'one')
     A    B         C         D
0  foo  one  0.542903  0.788896
6  foo  one -0.665189 -1.505290

('foo', 'three')
     A      B         C         D
7  foo  three -0.498339  0.534438

('foo', 'two')
     A    B         C         D
2  foo  two -0.903407  0.428031
4  foo  two -1.093602  0.837348

可以看到,name是一个2个元素的tuple,代表不同的列

g.get_group(('foo', 'one'))
ABCD
0fooone0.5429030.788896
6fooone-0.665189-1.505290

可以直接查询group后的某几列,生成Series或者子DataFrame

g['C']
<pandas.core.groupby.generic.SeriesGroupBy object at 0x00000123C33F64C8>
for name, group in g['C']:
    print(name)
    print(group)
    print(type(group))
    print()
('bar', 'one')
1   -0.375789
Name: C, dtype: float64
<class 'pandas.core.series.Series'>

('bar', 'three')
3   -1.564748
Name: C, dtype: float64
<class 'pandas.core.series.Series'>

('bar', 'two')
5   -0.202403
Name: C, dtype: float64
<class 'pandas.core.series.Series'>

('foo', 'one')
0    0.542903
6   -0.665189
Name: C, dtype: float64
<class 'pandas.core.series.Series'>

('foo', 'three')
7   -0.498339
Name: C, dtype: float64
<class 'pandas.core.series.Series'>

('foo', 'two')
2   -0.903407
4   -1.093602
Name: C, dtype: float64
<class 'pandas.core.series.Series'>

其实所有的聚合统计,都是在dataframe和series上进行的;

三、实例分组探索天气数据

fpath = "./datas/beijing_tianqi/beijing_tianqi_2018.csv"
df = pd.read_csv(fpath)
# 替换掉温度的后缀℃
df.loc[:, "bWendu"] = df["bWendu"].str.replace("℃", "").astype('int32')
df.loc[:, "yWendu"] = df["yWendu"].str.replace("℃", "").astype('int32')
df.head()
ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
02018-01-013-6晴~多云东北风1-2级592
12018-01-022-5阴~多云东北风1-2级491
22018-01-032-5多云北风1-2级281
32018-01-040-8东北风1-2级281
42018-01-053-6多云~晴西北风1-2级501
# 新增一列为月份
df['month'] = df['ymd'].str[:7]
df.head()
ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevelmonth
02018-01-013-6晴~多云东北风1-2级5922018-01
12018-01-022-5阴~多云东北风1-2级4912018-01
22018-01-032-5多云北风1-2级2812018-01
32018-01-040-8东北风1-2级2812018-01
42018-01-053-6多云~晴西北风1-2级5012018-01

1、查看每个月的最高温度

data = df.groupby('month')['bWendu'].max()
data
month
2018-01     7
2018-02    12
2018-03    27
2018-04    30
2018-05    35
2018-06    38
2018-07    37
2018-08    36
2018-09    31
2018-10    25
2018-11    18
2018-12    10
Name: bWendu, dtype: int32
type(data)
pandas.core.series.Series
data.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x123c344b308>

2、查看每个月的最高温度、最低温度、平均空气质量指数

df.head()
ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevelmonth
02018-01-013-6晴~多云东北风1-2级5922018-01
12018-01-022-5阴~多云东北风1-2级4912018-01
22018-01-032-5多云北风1-2级2812018-01
32018-01-040-8东北风1-2级2812018-01
42018-01-053-6多云~晴西北风1-2级5012018-01
group_data = df.groupby('month').agg({"bWendu":np.max, "yWendu":np.min, "aqi":np.mean})
group_data
bWenduyWenduaqi
month
2018-017-1260.677419
2018-0212-1078.857143
2018-0327-4130.322581
2018-04301102.866667
2018-05351099.064516
2018-06381782.300000
2018-07372272.677419
2018-08362059.516129
2018-09311150.433333
2018-1025167.096774
2018-1118-4105.100000
2018-1210-1277.354839
group_data.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x123c5502d48>


怎样使用Pandas批量拆分与合并Excel文件?

Pandas批量拆分Excel与合并Excel

实例演示:
1. 将一个大Excel等份拆成多个Excel
2. 将多个小Excel合并成一个大Excel并标记来源

work_dir="./course_datas/c15_excel_split_merge"
splits_dir=f"{work_dir}/splits"

import os
if not os.path.exists(splits_dir):
    os.mkdir(splits_dir)

0、读取源Excel到Pandas

import pandas as pd
df_source = pd.read_excel(f"{work_dir}/crazyant_blog_articles_source.xlsx")
df_source.head()
idtitletags
02585Tensorflow怎样接收变长列表特征python,tensorflow,特征工程
12583Pandas实现数据的合并concatpandas,python,数据分析
22574Pandas的Index索引有什么用途?pandas,python,数据分析
32564机器学习常用数据集大全python,机器学习
42561一个数据科学家的修炼路径数据分析
df_source.index
RangeIndex(start=0, stop=258, step=1)
df_source.shape
(258, 3)
total_row_count = df_source.shape[0]
total_row_count
258

一、将一个大Excel等份拆成多个Excel

  1. 使用df.iloc方法,将一个大的dataframe,拆分成多个小dataframe
  2. 将使用dataframe.to_excel保存每个小Excel

1、计算拆分后的每个excel的行数

# 这个大excel,会拆分给这几个人
user_names = ["xiao_shuai", "xiao_wang", "xiao_ming", "xiao_lei", "xiao_bo", "xiao_hong"]
# 每个人的任务数目
split_size = total_row_count // len(user_names)
if total_row_count % len(user_names) != 0:
    split_size += 1

split_size
43

2、拆分成多个dataframe

df_subs = []
for idx, user_name in enumerate(user_names):
    # iloc的开始索引
    begin = idx*split_size
    # iloc的结束索引
    end = begin+split_size
    # 实现df按照iloc拆分
    df_sub = df_source.iloc[begin:end]
    # 将每个子df存入列表
    df_subs.append((idx, user_name, df_sub))

3、将每个datafame存入excel

for idx, user_name, df_sub in df_subs:
    file_name = f"{splits_dir}/crazyant_blog_articles_{idx}_{user_name}.xlsx"
    df_sub.to_excel(file_name, index=False)

二、合并多个小Excel到一个大Excel

  1. 遍历文件夹,得到要合并的Excel文件列表
  2. 分别读取到dataframe,给每个df添加一列用于标记来源
  3. 使用pd.concat进行df批量合并
  4. 将合并后的dataframe输出到excel

1. 遍历文件夹,得到要合并的Excel名称列表

import os
excel_names = []
for excel_name in os.listdir(splits_dir):
    excel_names.append(excel_name)
excel_names
['crazyant_blog_articles_0_xiao_shuai.xlsx',
 'crazyant_blog_articles_1_xiao_wang.xlsx',
 'crazyant_blog_articles_2_xiao_ming.xlsx',
 'crazyant_blog_articles_3_xiao_lei.xlsx',
 'crazyant_blog_articles_4_xiao_bo.xlsx',
 'crazyant_blog_articles_5_xiao_hong.xlsx']

2. 分别读取到dataframe

df_list = []

for excel_name in excel_names:
    # 读取每个excel到df
    excel_path = f"{splits_dir}/{excel_name}"
    df_split = pd.read_excel(excel_path)
    # 得到username
    username = excel_name.replace("crazyant_blog_articles_", "").replace(".xlsx", "")[2:]
    print(excel_name, username)
    # 给每个df添加1列,即用户名字
    df_split["username"] = username

    df_list.append(df_split)
crazyant_blog_articles_0_xiao_shuai.xlsx xiao_shuai
crazyant_blog_articles_1_xiao_wang.xlsx xiao_wang
crazyant_blog_articles_2_xiao_ming.xlsx xiao_ming
crazyant_blog_articles_3_xiao_lei.xlsx xiao_lei
crazyant_blog_articles_4_xiao_bo.xlsx xiao_bo
crazyant_blog_articles_5_xiao_hong.xlsx xiao_hong

3. 使用pd.concat进行合并

df_merged = pd.concat(df_list)
df_merged.shape
(258, 4)
df_merged.head()
idtitletagsusername
02585Tensorflow怎样接收变长列表特征python,tensorflow,特征工程xiao_shuai
12583Pandas实现数据的合并concatpandas,python,数据分析xiao_shuai
22574Pandas的Index索引有什么用途?pandas,python,数据分析xiao_shuai
32564机器学习常用数据集大全python,机器学习xiao_shuai
42561一个数据科学家的修炼路径数据分析xiao_shuai
df_merged["username"].value_counts()
xiao_hong     43
xiao_bo       43
xiao_shuai    43
xiao_lei      43
xiao_wang     43
xiao_ming     43
Name: username, dtype: int64

4. 将合并后的dataframe输出到excel

df_merged.to_excel(f"{work_dir}/crazyant_blog_articles_merged.xlsx", index=False)

Tensorflow怎样接收变长列表特征

比如用户的分类偏好、用户的历史观影行为,都是变长的元素列表,怎么输入到模型?

这个问题很多人遇到,比如这些:

有几种方法,但都还没有完美解决问题:

1、multi-onehot

自己创建一个大数组,把变长元素对应位置设置为1;

比如这个特征有两个值:
值1:a、b、c
值2:b、c、d
那么词表是a、b、c、d
值1就变成了[1,1,1,0],值2变成了[0,1,1,1]

这种方式最灵活,因为如果遇到了带有权重的分类列表,也能搞定:
比如
值1:[(a,0.8), (b,0.7), (c, 0.6)]
值2:[(b,0.5), (c, 0.4), (d, 0.3)]
那么词表依然是a、b、c、d,但是对应权重却可以放到原来为1的位置上;
值1变成了:[0.8, 0.7, 0.6, 0]
值2变成了:[0, 0.5, 0.4, 0.3]

然而这种方法tensorflow的feature column不支持,只能自己做映射转换

2、变成定长

以下两种方式,tensorflow的feature column可以支持

变成定长方法1:截取前TOP N个元素

来自资料:
http://proceedings.mlr.press/v7/niculescu09
有个PDF,看截图:

使用的方法,是先计算每个词语的频率,然后去TOP10的频率;

对于这种方法,个人感觉,如果是用户的分类偏好(分类,权重)列表,可以按照权重排序,取TOP10;
也可以提取定长10个元素,并且反映了用户个性化的偏好;

变成定长方法2:使用padding补0

来自资料:tensorflow的官方文档
https://www.tensorflow.org/tutorials/text/text_classification_rnn

这是用0补齐的方式;

Pandas实现数据的合并concat

使用场景:

批量合并相同格式的Excel、给DataFrame添加行、给DataFrame添加列

一句话说明concat语法:

  • 使用某种合并方式(inner/outer)
  • 沿着某个轴向(axis=0/1)
  • 把多个Pandas对象(DataFrame/Series)合并成一个。

concat语法:pandas.concat(objs, axis=0, join=’outer’, ignore_index=False)

  • objs:一个列表,内容可以是DataFrame或者Series,可以混合
  • axis:默认是0代表按行合并,如果等于1代表按列合并
  • join:合并的时候索引的对齐方式,默认是outer join,也可以是inner join
  • ignore_index:是否忽略掉原来的数据索引

append语法:DataFrame.append(other, ignore_index=False)

append只有按行合并,没有按列合并,相当于concat按行的简写形式
* other:单个dataframe、series、dict,或者列表
* ignore_index:是否忽略掉原来的数据索引

参考文档:

  • pandas.concat的api文档:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.concat.html
  • pandas.concat的教程:https://pandas.pydata.org/pandas-docs/stable/user_guide/merging.html
  • pandas.append的api文档:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.append.html
import pandas as pd

import warnings
warnings.filterwarnings('ignore')

一、使用pandas.concat合并数据

df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
                    'B': ['B0', 'B1', 'B2', 'B3'],
                    'C': ['C0', 'C1', 'C2', 'C3'],
                    'D': ['D0', 'D1', 'D2', 'D3'],
                    'E': ['E0', 'E1', 'E2', 'E3']
                   })
df1
ABCDE
0A0B0C0D0E0
1A1B1C1D1E1
2A2B2C2D2E2
3A3B3C3D3E3
df2 = pd.DataFrame({ 'A': ['A4', 'A5', 'A6', 'A7'],
                     'B': ['B4', 'B5', 'B6', 'B7'],
                     'C': ['C4', 'C5', 'C6', 'C7'],
                     'D': ['D4', 'D5', 'D6', 'D7'],
                     'F': ['F4', 'F5', 'F6', 'F7']
                   })
df2
ABCDF
0A4B4C4D4F4
1A5B5C5D5F5
2A6B6C6D6F6
3A7B7C7D7F7

1、默认的concat,参数为axis=0、join=outer、ignore_index=False

pd.concat([df1,df2])
ABCDEF
0A0B0C0D0E0NaN
1A1B1C1D1E1NaN
2A2B2C2D2E2NaN
3A3B3C3D3E3NaN
0A4B4C4D4NaNF4
1A5B5C5D5NaNF5
2A6B6C6D6NaNF6
3A7B7C7D7NaNF7

2、使用ignore_index=True可以忽略原来的索引

pd.concat([df1,df2], ignore_index=True)
ABCDEF
0A0B0C0D0E0NaN
1A1B1C1D1E1NaN
2A2B2C2D2E2NaN
3A3B3C3D3E3NaN
4A4B4C4D4NaNF4
5A5B5C5D5NaNF5
6A6B6C6D6NaNF6
7A7B7C7D7NaNF7

3、使用join=inner过滤掉不匹配的列

pd.concat([df1,df2], ignore_index=True, join="inner")
ABCD
0A0B0C0D0
1A1B1C1D1
2A2B2C2D2
3A3B3C3D3
4A4B4C4D4
5A5B5C5D5
6A6B6C6D6
7A7B7C7D7

4、使用axis=1相当于添加新列

df1
ABCDE
0A0B0C0D0E0
1A1B1C1D1E1
2A2B2C2D2E2
3A3B3C3D3E3

A:添加一列Series

s1 = pd.Series(list(range(4)), name="F")
pd.concat([df1,s1], axis=1)
ABCDEF
0A0B0C0D0E00
1A1B1C1D1E11
2A2B2C2D2E22
3A3B3C3D3E33

B:添加多列Series

s2 = df1.apply(lambda x:x["A"]+"_GG", axis=1)
s2
0    A0_GG
1    A1_GG
2    A2_GG
3    A3_GG
dtype: object
s2.name="G"
pd.concat([df1,s1,s2], axis=1)
ABCDEFG
0A0B0C0D0E00A0_GG
1A1B1C1D1E11A1_GG
2A2B2C2D2E22A2_GG
3A3B3C3D3E33A3_GG
# 列表可以只有Series
pd.concat([s1,s2], axis=1)
FG
00A0_GG
11A1_GG
22A2_GG
33A3_GG
# 列表是可以混合顺序的
pd.concat([s1,df1,s2], axis=1)
FABCDEG
00A0B0C0D0E0A0_GG
11A1B1C1D1E1A1_GG
22A2B2C2D2E2A2_GG
33A3B3C3D3E3A3_GG

二、使用DataFrame.append按行合并数据

df1 = pd.DataFrame([[1, 2], [3, 4]], columns=list('AB'))
df1
AB
012
134
df2 = pd.DataFrame([[5, 6], [7, 8]], columns=list('AB'))
df2
AB
056
178

1、给1个dataframe添加另一个dataframe

df1.append(df2)
AB
012
134
056
178

2、忽略原来的索引ignore_index=True

df1.append(df2, ignore_index=True)
AB
012
134
256
378

3、可以一行一行的给DataFrame添加数据

# 一个空的df
df = pd.DataFrame(columns=['A'])
df
A

A:低性能版本

for i in range(5):
    # 注意这里每次都在复制
    df = df.append({'A': i}, ignore_index=True)
df
A
00
11
22
33
44

B:性能好的版本

# 第一个入参是一个列表,避免了多次复制
pd.concat(
    [pd.DataFrame([i], columns=['A']) for i in range(5)],
    ignore_index=True
)
A
00
11
22
33
44

Pandas的Index索引有什么用途?

把数据存储于普通的column列也能用于数据查询,那使用index有什么好处?

index的用途总结:
1. 更方便的数据查询;
2. 使用index可以获得性能提升;
3. 自动的数据对齐功能;
4. 更多更强大的数据结构支持;

import pandas as pd
df = pd.read_csv("./datas/ml-latest-small/ratings.csv")
df.head()
userIdmovieIdratingtimestamp
0114.0964982703
1134.0964981247
2164.0964982224
31475.0964983815
41505.0964982931
df.count()
userId       100836
movieId      100836
rating       100836
timestamp    100836
dtype: int64

1、使用index查询数据

# drop==False,让索引列还保持在column
df.set_index("userId", inplace=True, drop=False)
df.head()
userIdmovieIdratingtimestamp
userId
1114.0964982703
1134.0964981247
1164.0964982224
11475.0964983815
11505.0964982931
df.index
Int64Index([  1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
            ...
            610, 610, 610, 610, 610, 610, 610, 610, 610, 610],
           dtype='int64', name='userId', length=100836)
# 使用index的查询方法
df.loc[500].head(5)
userIdmovieIdratingtimestamp
userId
50050014.01005527755
500500111.01005528017
500500391.01005527926
5005001011.01005527980
5005001044.01005528065
# 使用column的condition查询方法
df.loc[df["userId"] == 500].head()
userIdmovieIdratingtimestamp
userId
50050014.01005527755
500500111.01005528017
500500391.01005527926
5005001011.01005527980
5005001044.01005528065

2. 使用index会提升查询性能

  • 如果index是唯一的,Pandas会使用哈希表优化,查询性能为O(1);
  • 如果index不是唯一的,但是有序,Pandas会使用二分查找算法,查询性能为O(logN);
  • 如果index是完全随机的,那么每次查询都要扫描全表,查询性能为O(N);

实验1:完全随机的顺序查询

# 将数据随机打散
from sklearn.utils import shuffle
df_shuffle = shuffle(df)
df_shuffle.head()
userIdmovieIdratingtimestamp
userId
16016023401.0985383314
12912911363.51167375403
167167441914.51154718915
5365362763.0832839990
676759522.01501274082
# 索引是否是递增的
df_shuffle.index.is_monotonic_increasing
False
df_shuffle.index.is_unique
False
# 计时,查询id==500数据性能
%timeit df_shuffle.loc[500]
376 µs ± 52.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

实验2:将index排序后的查询

df_sorted = df_shuffle.sort_index()
df_sorted.head()
userIdmovieIdratingtimestamp
userId
1129854.0964983034
1126172.0964982588
1136394.0964982271
1164.0964982224
117334.0964982400
# 索引是否是递增的
df_sorted.index.is_monotonic_increasing
True
df_sorted.index.is_unique
False
%timeit df_sorted.loc[500]
203 µs ± 20.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

3. 使用index能自动对齐数据

包括series和dataframe

s1 = pd.Series([1,2,3], index=list("abc"))
s1
a    1
b    2
c    3
dtype: int64
s2 = pd.Series([2,3,4], index=list("bcd"))
s2
b    2
c    3
d    4
dtype: int64
s1+s2
a    NaN
b    4.0
c    6.0
d    NaN
dtype: float64

4. 使用index更多更强大的数据结构支持

很多强大的索引数据结构
* CategoricalIndex,基于分类数据的Index,提升性能;
* MultiIndex,多维索引,用于groupby多维聚合后结果等;
* DatetimeIndex,时间类型索引,强大的日期和时间的方法支持;

机器学习常用数据集大全

UCI Machine Learning Adult Dataset

Business Problem: Classification (a person earns more than 50k or less) Predictor Variable: Label ; Predictors: country, age, education, occupation, marital status etc.

文章:https://towardsdatascience.com/pandas-index-explained-b131beaf6f7b
数据集地址:https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data

Kaggle – Avazu:Click-Through Rate Prediction

Predict whether a mobile ad will be clicked
In online advertising, click-through rate (CTR) is a very important metric for evaluating ad performance. As a result, click prediction systems are essential and widely used for sponsored search and real-time bidding.

Kaggle地址:
https://www.kaggle.com/c/avazu-ctr-prediction/overview

UCI – Adult Data Set $50k

Predict whether income exceeds $50K/yr based on census data. Also known as “Census Income” dataset
https://archive.ics.uci.edu/ml/datasets/Adult

UCI – Iris Data Set

This is perhaps the best known database to be found in the pattern recognition literature. Fisher’s paper is a classic in the field and is referenced frequently to this day
https://archive.ics.uci.edu/ml/datasets/Iris

Kaggle Titanic: Machine Learning from Disaster

use machine learning to create a model that predicts which passengers survived the Titanic shipwreck.

https://www.kaggle.com/c/titanic

Pandas的axis参数怎么理解?

axis参数非常的让人困惑难以理解,本视频我会用形象化的方式讲解一下这个参数,核心要诀就是axis那个轴会消失!

  • axis=0或者”index”:
    • 如果是单行操作,就指的是某一行
    • 如果是聚合操作,指的是跨行cross rows
  • axis=1或者”columns”:
    • 如果是单列操作,就指的是某一列
    • 如果是聚合操作,指的是跨列cross columns

按哪个axis,就是这个axis要动起来(类似被for遍历),其它的axis保持不动

import pandas as pd
import numpy as np
df = pd.DataFrame(
    np.arange(12).reshape(3,4),
    columns=['A', 'B', 'C', 'D']
)
df
ABCD
00123
14567
2891011

1、单列drop,就是删除某一列

# 代表的就是删除某列
df.drop("A", axis=1)
BCD
0123
1567
291011

2、单行drop,就是删除某一行

df
ABCD
00123
14567
2891011
# 代表的就是删除某行
df.drop(1, axis=0)
ABCD
00123
2891011

3、按axis=0/index执行mean聚合操作

反直觉:输出的不是每行的结果,而是每列的结果

df
ABCD
00123
14567
2891011
# axis=0 or axis=index
df.mean(axis=0)
A    4.0
B    5.0
C    6.0
D    7.0
dtype: float64

指定了按哪个axis,就是这个axis要动起来(类似被for遍历),其它的axis保持不动

4、按axis=1/columns执行mean聚合操作

反直觉:输出的不是每行的结果,而是每列的结果

df
ABCD
00123
14567
2891011
# axis=1 or axis=columns
df.mean(axis=1)
0    1.5
1    5.5
2    9.5
dtype: float64

指定了按哪个axis,就是这个axis要动起来(类似被for遍历),其它的axis保持不动

5、再次举例,加深理解

def get_sum_value(x):
    return x["A"] + x["B"] + x["C"] + x["D"]

df["sum_value"] = df.apply(get_sum_value, axis=1)
df
ABCDsum_value
001236
1456722
289101138

指定了按哪个axis,就是这个axis要动起来(类似被for遍历),其它的axis保持不动

本文地址:http://www.crazyant.net/2546.html
转载请注明来源