Pandas基础使用11~20
11 Pandas的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.drop('A', axis=1)
df.drop(1, axis=0)
# 按照axis进行聚合操作
df.mean(axis=0)
# 使用自定义函数
def get_sum_value(x):
return x['A'] + x['B'] + x["C"] + x["D"]
df['sum_value'] = df.apply(get_sum_value, axis=1)
12 pandas的索引用途
把数据存储于普通的column列也能用于数据查询,那使用index有什么好处?
index的用途总结:
- 更方便的数据查询;
- 使用index可以获得性能提升;
- 自动的数据对齐功能;
- 更多更强大的数据结构支持
import pandas as pd
df = pd.read_csv("./datas/ml-latest-small/ratings.csv")
# 使用index查询数据,让索引列还保留在column,并替换原索引列
df.set_index('userId', inplace=True, drop=False)
# 使用index的查询方法,查询index为500的行
df.loc[500].head(5)
# 使用column的condition方法查询
df.loc[df['userId']==500].head(5)
# 将数据随机打散
from sklearn.utils import shuffle
df_shuffle = shuffle(df)
# 判断索引是否为递增和唯一
df_shuffle.index.is_monotonic_increasing
df_shuffle.index.is_unique
%timeit df_shuffle.loc[500]
# 将index排序后进行查询
df_sorted = df_shuffle.sort_index()
# 使用index可以自动对齐数据
s1 = pd.Series([1,2,3], index=list('abc'))
s2 = pd.Series([2,3,4], index=list("bcd"))
s1+s2 # 将对齐索引对应的value相加,不对齐的输出None
13 Pandas实现DataFrame的Merge
Pandas的Merge,相当于Sql的Join,将不同的表按key关联到一个表
merge的语法:
pd.merge(left, right, how=‘inner’, on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=True, suffixes=(‘x’, ‘y’), copy=True, indicator=False, validate=None)
- left,right:要merge的dataframe或者有name的Series
- how:join类型,‘left’, ‘right’, ‘outer’, ‘inner’
- on:join的key,left和right都需要有这个key
- left_on:left的df或者series的key
- right_on:right的df或者seires的key
- left_index,right_index:使用index而不是普通的column做join
- suffixes:两个元素的后缀,如果列有重名,自动添加后缀,默认是(’_x’, ‘_y’)
文档地址:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.merge.html
本次讲解提纲:
- 电影数据集的join实例
- 理解merge时一对一、一对多、多对多的数量对齐关系
- 理解left join、right join、inner join、outer join的区别
- 如果出现非Key的字段重名怎么办
1、电影数据集的join实例
电影评分数据集
是推荐系统研究的很好的数据集
位于本代码目录:./datas/movielens-1m
包含三个文件:
- 用户对电影的评分数据 ratings.dat
- 用户本身的信息数据 users.dat
- 电影本身的数据 movies.dat
可以关联三个表,得到一个完整的大表
数据集官方地址:https://grouplens.org/datasets/movielens/
import pandas as pd
df_ratings = pd.read_csv(
"./datas/movielens-1m/ratings.dat",
sep="::",
engine='python',
names="UserID::MovieID::Rating::Timestamp".split("::")
)
df_users = pd.read_csv(
"./datas/movielens-1m/users.dat",
sep="::",
engine='python',
names="UserID::Gender::Age::Occupation::Zip-code".split("::")
)
df_movies = pd.read_csv(
"./datas/movielens-1m/movies.dat",
sep="::",
engine='python',
names="MovieID::Title::Genres".split("::")
)
df_ratings_users = pd.merge(
df_ratings, df_users, left_on="UserID", right_on="UserID", how="inner"
)
df_ratings_users_movies = pd.merge(
df_ratings_users, df_movies, left_on="MovieID", right_on="MovieID", how="inner"
)
left = pd.DataFrame({'sno': [11, 12, 13, 14],
'name': ['name_a', 'name_b', 'name_c', 'name_d']
})
right = pd.DataFrame({'sno': [11, 12, 13, 14],
'age': ['21', '22', '23', '24']
})
# 一对一关系,结果中有4条
pd.merge(left, right, on='sno')
14 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:是否忽略掉原来的数据索引
import pandas as pd
import warnings
# 忽略warnings
warnings.filterwarnings('ignore')
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']
})
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']
})
# 合并两个DataFrame
pd.concat([df1, df2], ignore_index=True, join='inner', axis=0)
# 使用axis添加新列
s1 = pd.Series(list(range(4)), name='F')
pd.concat([df1, s1], axis=1)
# 添加多列
s2 = df1.apply(lambda x:x['A']+'_GG', axis=1)
s1.name = 'G'
pd.concat([df1, s1, s2], axis=1)
pd.concat([s1,s2], axis=1)
15 Pandas批量拆分Excel于合并Excel
import os
import pandas as pd
work_dir='./course_datas/c15_excel_split_merge'
splits_dir = f'{work_dir}/splits'
if not os.path.exists(splits_dir):
os.mkdir(splits_dir)
df_source = pd.read_excel(f"{work_dir}/crazyant_blog_articles_source.xlsx")
total_row_count = df_source.shape[0] # 查看多少行
# 使用df.iloc方法,拆分DataFrame
# 将大的表格拆分给几个人
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
# 拆分成多个DataFrame
df_subs = []
for idx, user_names in enumerate(user_names):
# iloc的开始索引
begin = idx * split_size
# ilox结束索引
end = begin + split_size
# 实现df按照iloc拆分
df_sub = df_source.iloc[begin:end]
# 将每个子df存入列表
df_subs.append((idx, user_name, df_sub))
# 将每个dataframe存入excel
for idx, user_name, df_sub in df_subs:
file_name = f'{splits_dir}/assignments_{idx}_{user_name}.xlsx'
df_sub.to_excel(file_name, index=False)
# 合并多个小Excel到一个大Excel
import os
# 得到多个表格路径的列表
excel_names = []
for excel_name in os.listdir(split_dir):
excel_name.append(excel_name)
# 分别读取到dataframe
df_list = []
for excel_name in excel_names:
excel_path = f'{splits_dir}/{excel_name}'
df_split = pd.read_excel(excel_path)
# 得到username
user_name = excel_name.replace('assignments_','').replace('.xlsx', '')[2:]
# 给每个df添加1列,即username
df_split['username'] = username
df_list.append(df_split)
df_merged = pd.concat(df_list)
df_merged['username'].vlue_counts()
df_merged.to_excel(f'{work_dir}/assignments_merged.xlsx', index=False)
16 Pandas实现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)})
# 单个列groupby,查询所有数据列的统计信息
df.groupby('A').sum
# 多个列groupby,查询所有数据列的统计
df.groupby(['A', 'B']).mean()
# 同时查询多种数据的统计
df.groupby('A').agg([np.sum, np.mean, np.std])
# 查看单列的数据统计结果,使用agg方法
# 方法1:预过滤,性能更好
df.groupby('A')['c'].agg([np.sum, np.mean, np.std])
# 方法2
df.groupby('A').agg([np.sum, np.mean, np.std])['C']
# 不同列使用不同的聚合函数,使用字典
df.groupby('A').agg({'C':n, 'D':np.mean})
# 遍历单个列聚合的分组
g = df.groupby('A')
for name, group in g:
print(name)
print(group)
# 获取单个分组的数据,get_group()方法
g.get_group('bar')
# 多个列的聚类
g = df.groupby(['A', 'B'])
g.get_group(('foo', 'one'))
# 直接查询group后的几列,生成Series或DataFrame
g['C']
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]
# 查看每个月的最高温度
data = df.groupby('month')['bWendu'].max()
data.plot()
# 查看每个月的最高温度、最低温度、平均空气质量指数
group_data = df.groupby('mouth').agg({'bWendu':np.max, 'yWendu':np.min, 'aqi':np.mean})
group_data.plot()
17 Pandas的分层索引Mutilindex
为什么要学习分层索引MultiIndex?
- 分层索引:在一个轴向上拥有多个索引层级,可以表达更高维度数据的形式;
- 可以更方便的进行数据筛选,如果有序则性能更好;
- groupby等操作的结果,如果是多KEY,结果是分层索引,需要会使用
- 一般不需要自己创建分层索引(MultiIndex有构造函数但一般不用)
import pandas as pd
%matplotlib inline
stocks = pd.read_excel('./datas/stocks/互联网公司股票.xlsx')
stocks["公司"].unique()
stocks.index
stocks.groupby('公司')["收盘"].mean()
ser = stocks.groupby(['公司', '日期'])['收盘'].mean()
ser.index
# unstack把二级索引变为列
ser.unstack()
ser.reset_index()
# Series多层索引筛选数据
ser.loc['BIDU']
ser.loc[('BIDU','2019-10-02')]
ser.loc[:'2019-10-02']
# DataFrame多层索引
stocks.set_index(['公司', '日期'], inplace=True)
stocks.sort_index(inplace=True)
# 筛选数据
stocks.loc['BIDU']
stocks.loc[('BIDU', '2019-10-02'), :]
stocks.loc[('BIDU', '2019-10-02'), '开盘']
stocks.loc[['BIDU', 'JD'], :]
stocks.loc[(['BIDU', 'JD'], '2019-10-03'), :]
stocks.loc[('BIDU', ['2019-10-02', '2019-10-03']), '收盘']
# slice(None)代表筛选这一索引的所有内容
stocks.loc[(slice(None), ['2019-10-02', '2019-10-03']), :]
stocks.reset_index()
18 Pandas的数据转换函数map、apply、applymap
- map:只用于Series,实现每个值->值的映射;
- apply:用于Series实现每个值的处理,用于Dataframe实现某个轴的Series的处理;
- applymap:只能用于DataFrame,用于处理该DataFrame的每个元素;
import pandas as pd
stocks = pd.read_excel('./datas/stocks/互联网公司股票.xlsx')
stocks['公司'].unique()
# 公司股票代码到中文的映射,注意这里是小写
dict_company_names = {
"bidu": "百度",
"baba": "阿里巴巴",
"iq": "爱奇艺",
"jd": "京东"
}
# 方法1:Series.map(dict)
stocks['公司中文1'] = stocks['公司'].str.lower().map(dict_company_names)
# 方法2:Series.map(function)
stocks['公司中文2'] = stocks['公司'].map(lambda x:dict_company_names[x.lower()])
# apply 用于Series和DataFrame转换
stocks['公司中文3'] = stocks['公司'].apply(lambda x:dict_company_names[x.lower()])
# 在DataFrame上调用apply()方法,注意要设置指定的轴
stocks['公司中文4'] = stocks.apply(lambda x:dict_company_name[x['公司'].lower(), axis=1)
# applymap用于DataFrame所有值的转换
sub_df = stocks[['收盘', '开盘', '高', '低', '交易量']]
# 将这些数字取整数,应用于所有元素
sub_df.applymap(lambda x : int(x))
# 直接修改原df的这几列
stocks.loc[:, ['收盘', '开盘', '高', '低', '交易量']] = sub_df.applymap(lambda x : int(x))
19 Pandas对每个分组应用apply函数
1.对数值列按分组归一化
import pandas as pd
ratings = pd.read_csv(
"./datas/movielens-1m/ratings.dat",
sep="::",
engine='python',
names="UserID::MovieID::Rating::Timestamp".split("::")
)
# 实现按照用户ID分组,然后对每一列进行归一化
def rating_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(rating_norm)
ratings[rating['UserID']==1].head()
# 获取每个分组的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]
def get_wendu_topN(df, topn):
'''
这里的df,是每个月份分组group的df
'''
return df.sort_values(by = 'bWendu')[['ymd','bWendu']][-topn:]
df.groupby('mouth').apply(get_wendu_topN, topn=2)
20 Pandas的stack和pivot实现数据透视变换
- 经过统计得到多维度指标数据
- 使用unstack实现数据二维透视
- 使用pivot简化透视
- stack、unstack、pivot的语法
实例:统计得到’电影评分数据集‘,每个月份的每个分数被评分多少次:(月份、分数(1~5)、次数)
import pandas as pd
import numpy as np
%matplotlib inline
df = pd.read_csv(
"./datas/movielens-1m/ratings.dat",
header=None,
names="UserID::MovieID::Rating::Timestamp".split("::"),
sep="::",
engine="python"
)
# 时间戳转化为日期时间
df['pdata'] = pd.to_datatime(df['Timestamp'], unit='s')
# 实现数据统计,pv为新的列,记录次数
df_group = df.groupby([df['pdata'].dt.month, 'Rating'])['UserID'].agg(pv=np.size)
# 使用unstack进行数据二维透视
df_stack = df_group.unstack()
df_stack.plot()
# unstack和stack是互逆操作
df_stack.stack().head(20)
# 使用pivot简化透视
df_reset = df_group.reset_index()
df_pivot = df_reset.pivot("pdate", "Rating", "pv")
df_pivot.plot()
本文深入讲解Pandas库的基础与进阶使用,包括理解axis参数、利用索引高效查询、DataFrame的Merge操作、数据合并Concat、批量拆分与合并Excel、groupby分组统计、分层索引MultiIndex、数据转换函数map、apply、applymap,以及对每个分组应用apply函数。通过实例演示了如何进行数据处理和分析,如电影评分数据集的join操作、数据透视变换等。

934

被折叠的 条评论
为什么被折叠?



