带你从数据小白成长为数据分析师
import pandas as pd
import numpy as np
pd.read_csv(filename): 从CSV文件导入数据
pd.read_excel(filename): 从Excel文件导入数据
pd.read_table(filename): 从限定分隔符的文本文件导入数据
pd.read_json(json_string): 从JSON格式的字符串导入数据
pd.read_SQL(query, connection_object): 从SQL表/库导入数据
pd.read_html(url): 解析URL、字符串或者HTML文件
pd.read_clipboard(): 从粘贴板获取内容
pd.DataFrame(dict): 从字典对象导入数据
# 读取中文路径
path = open(r'.\data.csv')
# csv文件是gbk格式:open(r'.\文档\data.csv','rb')
pd.read_csv(path, sep='\t', skiprows=[0], nrows=0, na_values='1.#INF')
path.close
pd.read_csv(filepath_or_buffer: Union[str, pathlib.Path, IO[~AnyStr]],
sep=',', delimiter=None, header='infer', names=None, index_col=None,
usecols=None, squeeze=False, prefix=None, mangle_dupe_cols=True,
dtype=None, engine=None, converters=None, true_values=None,
false_values=None, skipinitialspace=False, skiprows=None,
skipfooter=0, nrows=None, na_values=None, keep_default_na=True,
na_filter=True, verbose=False, skip_blank_lines=True,
parse_dates=False, infer_datetime_format=False,
keep_date_col=False, date_parser=None, dayfirst=False,
cache_dates=True, iterator=False, chunksize=None,
compression='infer', thousands=None, decimal: str = '.',
lineterminator=None, quotechar='"', quoting=0,
doublequote=True, escapechar=None, comment=None,
encoding=None, dialect=None, error_bad_lines=True,
warn_bad_lines=True, delim_whitespace=False,
low_memory=True, memory_map=False, float_precision=None)
参数名 | 含义 | 输入 | 默认 | pd.read_csv(用例) | 注释 |
---|---|---|---|---|---|
filepath _or_buffer |
文件路径 | str | 必填 | (r’.\data.csv’) | 可以是url或本地路径 |
sep | 指定分隔符 | str | ’,’ | (./data.csv, sep = ‘\t’) |
可用正则表达式 |
header | 指定行作为表头 数据开始于下行 |
int or list[int] | ‘infer’ | (./data.csv, header = None) |
数据中没有表头则需设置为None 默认会自动判断把第一行作为表头 |
names | 设定列名 | array-like | None | (./data.csv, names = namelist) |
没有表头时使用,同时设置header=None |
dtype | 每列数据的数据类型 | str or dict | None | (./data.csv, dtype = {‘time’: str, ‘ID’: int}) |
|
usecols | 使用部分列 | list[int] or list[str] | None | (./data.csv, usecols=[0,4,3]) |
默认不按顺序,按顺序方法:(./data.csv, usecols= lambda x: x.upper() in [‘COL3’,’COL1’]) |
skiprows | 跳过指定行 | int list[int] | None | (./data.csv, skiprows=range(2)) |
从文件头开始算起 |
skipfooter | 尾部跳过 | int list[int] | None | (./data.csv, skipfooter=1) |
用例为跳过最后一行 c引擎不支持 |
nrows | 读取的行数 | int | None | (./data.csv, nrows=1000) |
从文件头开始算起 |
true_values | 真值转换 | list | None | (./data.csv, true_values=[‘Yes’]) | |
false_values | 假值转换 | list | None | (./data.csv, false_values=[‘No’]) | |
na_values | 空值替换 | str list dict |
None | (./data.csv, na_values=[“0”]) |
str: ‘NA’ list: [“0”,”无”] dict: {‘col’:0, 1:[“无”]}指定列的指定值设NaN |
keep_default_na | 保留默认空值 | bool | True | (./data.csv, keep_default_na=False) |
设定为False时 只依靠na_values判断空值 |
skip_blank_lines | 跳过空行 | bool | True | (./data.csv, skip_blank_lines=False) |
如果为True,则跳过空行;否则记为NaN。 |
parse_dates | 日期时间解析 | bool list dict | False | (./data.csv, parse_dates=True) |
指定日期时间字段进行解析: parse_dates=[‘年份’] 将1,4列合并为‘time’时间类型列 parse_dates={‘time’:[1,4]} |
infer_datetime_format | 自动识别日期时间 | bool | False | (./data.csv, parse_dates=True, infer_datetime_format=True) |
按用例方法,自动识别并解析,无需指定 |
df.to_csv(filename):导出数据到CSV文件
df.to_excel(filename):导出数据到Excel文件
df.to_sql(table_name, connection_object):导出数据到SQL表
df.to_json(filename):以Json格式导出数据到文本文件
DataFrame.to_csv(path_or_buf=None, sep=', ', na_rep='',
float_format=None, columns=None,
header=True, index=True, index_label=None, mode='w',
encoding=None, compression=None,
quoting=None, quotechar='"', line_terminator='\n',
chunksize=None, tupleize_cols=None,
date_format=None, doublequote=True, escapechar=None, decimal='.')
参数名 | 含义 | 输入 | 默认 | 注释 |
---|---|---|---|---|
path_or_buf | 导出路径 | string or file handle | None | 如果没有提供,结果将返回为字符串 |
sep | 输出文件的字段分隔符 | character | ‘,’ | |
columns | 列顺序 | None | 可选列写入 | |
index | 是否输出index | boolean | True | |
encoding | 编码格式 | string | None | Python 3上默认为“UTF-8” |
date_format | 字符串对象转换为日期时间对象 | string | None | |
decimal | 字符识别为小数点分隔符 | string | ‘.’ | 欧洲数据使用 ’,’ |
df.shape():查看行数和列数
df.info():查看索引、数据类型和内存信息
df.describe():查看数值型列的汇总统计
s.value_counts(dropna=False):查看Series对象的唯一值和计数
df.apply(pd.Series.value_counts):查看DataFrame对象中每一列的唯一值和计数
数据切片主要使用loc与iloc,loc指定列名,iloc指定位置
df = pd.read_csv(".\data_csv.csv", encoding = "gbk")
print("示例数据:")
df
示例数据:
ID | 姓名 | 年龄 | 日期 | |
---|---|---|---|---|
0 | 1 | 张三 | 30 | 2021年2月26日 |
1 | 2 | 李四 | 40 | 2021年2月27日 |
2 | 3 | 王五 | 50 | 2021年2月26日 |
3 | 4 | 赵六 | 50 | 2021年2月28日 |
DataFrame.loc[ 行索引名称或条件 , 列索引名称 ] # 闭区间(含最后一个值)
df.loc[1] # 显示第2行数据,返回Series
ID 2
姓名 李四
年龄 40
日期 2021年2月27日
Name: 1, dtype: object
df.loc[1, '日期'] # 显示列名为“日期”,行数为2的数据
'2021年2月27日'
df.loc[2:,['姓名','年龄']]
姓名 | 年龄 | |
---|---|---|
2 | 王五 | 50 |
3 | 赵六 | 50 |
df.loc[df['年龄'] > 45]
ID | 姓名 | 年龄 | 日期 | |
---|---|---|---|---|
2 | 3 | 王五 | 50 | 2021年2月26日 |
3 | 4 | 赵六 | 50 | 2021年2月28日 |
df.loc[df['年龄'] > 45, ["姓名"]]
姓名 | |
---|---|
2 | 王五 |
3 | 赵六 |
df.loc[lambda df: df['年龄'] == 50, ["姓名"]]
姓名 | |
---|---|
2 | 王五 |
3 | 赵六 |
更多条件切片参考:https://zhuanlan.zhihu.com/p/87334662
DataFrame.iloc[ 行索引位置 , 列索引位置 ] # 开区间(不含最后一个值)
df.iloc[1] # 显示第2行数据,返回Series
ID 2
姓名 李四
年龄 40
日期 2021年2月27日
Name: 1, dtype: object
df.iloc[1,3]
'2021年2月27日'
df.iloc[2:, 1:3] # 同df.iloc[2:, [1,2]]
姓名 | 年龄 | |
---|---|---|
2 | 王五 | 50 |
3 | 赵六 | 50 |
df.iloc[lambda x: x.index % 2 == 0] # 取偶数行
ID | 姓名 | 年龄 | 日期 | |
---|---|---|---|---|
0 | 1 | 张三 | 30 | 2021年2月26日 |
2 | 3 | 王五 | 50 | 2021年2月26日 |
df = pd.read_csv(".\data_csv.csv", encoding = "gbk")
print("示例数据:")
df
示例数据:
ID | 姓名 | 年龄 | 日期 | |
---|---|---|---|---|
0 | 1 | 张三 | 30 | 2021年2月26日 |
1 | 2 | 李四 | 40 | 2021年2月27日 |
2 | 3 | 王五 | 50 | 2021年2月26日 |
3 | 4 | 赵六 | 50 | 2021年2月28日 |
会用到的函数:drop 与 loc
loc介绍过了,介绍一下drop
drop
DataFrame.drop(labels=None, axis=0, index=None, columns=None, inplace=False)
labels:要删除的行列的名字,用列表给定
axis:默认0,删除行;1,删除列
index:直接指定要删除的行
columns:直接指定要删除的列
inplace:True,修改了原始数据;默认False,不修改原始数据,返回新DataFrame
单独添加一个数据方法,未添加的行显示为NaN空值
df.loc[0,"性别"] = "男"
df
ID | 姓名 | 年龄 | 日期 | 性别 | |
---|---|---|---|---|---|
0 | 1 | 张三 | 30 | 2021年2月26日 | 男 |
1 | 2 | 李四 | 40 | 2021年2月27日 | NaN |
2 | 3 | 王五 | 50 | 2021年2月26日 | NaN |
3 | 4 | 赵六 | 50 | 2021年2月28日 | NaN |
添加一列为统一值
df.loc[:,"性别"] = "男"
df
ID | 姓名 | 年龄 | 日期 | 性别 | |
---|---|---|---|---|---|
0 | 1 | 张三 | 30 | 2021年2月26日 | 男 |
1 | 2 | 李四 | 40 | 2021年2月27日 | 男 |
2 | 3 | 王五 | 50 | 2021年2月26日 | 男 |
3 | 4 | 赵六 | 50 | 2021年2月28日 | 男 |
添加一列为不同值,注意list长度需要与行数相同
df.loc[:,"性别"] = ["男","女","男","女"]
# 同df["性别"] = ["男","女","男","女"]
df
ID | 姓名 | 年龄 | 日期 | 性别 | |
---|---|---|---|---|---|
0 | 1 | 张三 | 30 | 2021年2月26日 | 男 |
1 | 2 | 李四 | 40 | 2021年2月27日 | 女 |
2 | 3 | 王五 | 50 | 2021年2月26日 | 男 |
3 | 4 | 赵六 | 50 | 2021年2月28日 | 女 |
删除增加的这一列
df.drop(labels = ["性别"], axis = 1, inplace=True)
df
# 同df.drop(columns = "性别")
ID | 姓名 | 年龄 | 日期 | |
---|---|---|---|---|
0 | 1 | 张三 | 30 | 2021年2月26日 |
1 | 2 | 李四 | 40 | 2021年2月27日 |
2 | 3 | 王五 | 50 | 2021年2月26日 |
3 | 4 | 赵六 | 50 | 2021年2月28日 |
在最后一行添加数据
df.loc[df.shape[0]] = [5, "阿七", 35, '2021年3月01日']
df
ID | 姓名 | 年龄 | 日期 | |
---|---|---|---|---|
0 | 1 | 张三 | 30 | 2021年2月26日 |
1 | 2 | 李四 | 40 | 2021年2月27日 |
2 | 3 | 王五 | 50 | 2021年2月26日 |
3 | 4 | 赵六 | 50 | 2021年2月28日 |
4 | 5 | 阿七 | 35 | 2021年3月01日 |
在第一行添加数据
df.loc[-1] = [0, "老二", 40, '2021年3月01日'] # 增加一行
df.index = df.index + 1 # 把index的每一项增加1
df
ID | 姓名 | 年龄 | 日期 | |
---|---|---|---|---|
1 | 1 | 张三 | 30 | 2021年2月26日 |
2 | 2 | 李四 | 40 | 2021年2月27日 |
3 | 3 | 王五 | 50 | 2021年2月26日 |
4 | 4 | 赵六 | 50 | 2021年2月28日 |
5 | 5 | 阿七 | 35 | 2021年3月01日 |
0 | 0 | 老二 | 40 | 2021年3月01日 |
df.drop(labels = [0, 5], inplace=True)
df
ID | 姓名 | 年龄 | 日期 | |
---|---|---|---|---|
1 | 1 | 张三 | 30 | 2021年2月26日 |
2 | 2 | 李四 | 40 | 2021年2月27日 |
3 | 3 | 王五 | 50 | 2021年2月26日 |
4 | 4 | 赵六 | 50 | 2021年2月28日 |
df.drop_duplicates()
添加和删除行后,需要处理index,有set_index、sort_index()与reset_index()三种方法
set_index: 将 DataFrame 中的列转化为行索引。
DataFrame.set_index(keys, drop=True, append=False, inplace=False, verify_integrity=False)
keys:设置索引
append:添加新索引
drop:默认Ture,不保留原索引;False,保留原索引在新列
inplace:True,修改了原始数据;默认False,不修改原始数据,返回新DataFrame
sort_index:给index排序
DataFrame.sort_index(axis=0, level=None, ascending=True, inplace=False, kind=’quicksort’, na_position=’last’, sort_remaining=True, by=None)
axis:0按照行名排序;1按照列名排序
ascending:默认True升序排列;False降序排列
inplace:True,修改了原始数据;默认False,不修改原始数据,返回新DataFrame
reset_index:重置index
DataFrame.reset_index(level=None, drop=False, inplace=False, col_level=0, col_fill=”)
drop:True,不保留原索引;默认False,保留原索引在新列
inplace:True,修改了原始数据;默认False,不修改原始数据,返回新DataFrame
修改index
df.index = [7,6,4,8]
df
ID | 姓名 | 年龄 | 日期 | |
---|---|---|---|---|
7 | 1 | 张三 | 30 | 2021年2月26日 |
6 | 2 | 李四 | 40 | 2021年2月27日 |
4 | 3 | 王五 | 50 | 2021年2月26日 |
8 | 4 | 赵六 | 50 | 2021年2月28日 |
给index排序
df.sort_index(inplace = True)
df
ID | 姓名 | 年龄 | 日期 | |
---|---|---|---|---|
4 | 3 | 王五 | 50 | 2021年2月26日 |
6 | 2 | 李四 | 40 | 2021年2月27日 |
7 | 1 | 张三 | 30 | 2021年2月26日 |
8 | 4 | 赵六 | 50 | 2021年2月28日 |
重置index
df.reset_index(drop=True, inplace = True)
df
ID | 姓名 | 年龄 | 日期 | |
---|---|---|---|---|
0 | 3 | 王五 | 50 | 2021年2月26日 |
1 | 2 | 李四 | 40 | 2021年2月27日 |
2 | 1 | 张三 | 30 | 2021年2月26日 |
3 | 4 | 赵六 | 50 | 2021年2月28日 |
df = pd.read_excel(".\data_excel.xlsx")
print("示例数据:")
df.head()
示例数据:
订单编号 | 订单日期 | 数量 | 产品名称 | 产品类型 | 产品描述 | 产品单价 | |
---|---|---|---|---|---|---|---|
0 | 1 | 2020-07-06 | 10 | 中性笔 | 文具 | 0.5规格中性笔 | ¥1 |
1 | 1 | 2020-07-06 | 2 | 透明胶 | 办公用品 | NaN | ¥3 |
2 | 1 | 2020-07-06 | 3 | 裁纸刀 | 办公用品 | NaN | ¥5 |
3 | 2 | 2020-07-06 | 3 | 中性笔 | 文具 | NaN | ¥1 |
4 | 2 | 2020-07-06 | 1 | 橡皮擦 | 文具 | NaN | ¥3 |
方法一:使用split,使用split需要用str将数据集转化为字符串
Series.str.split(sep,n,expand=false)从前往后切分
Series.str.rsplit(sep,n,expand=false)从后往前切分
sep表示用于分割的字符,n表格分割成多少列;expand:True输出Dataframe,False输出Series。
df.loc[:,"单价"] = df.loc[:,"产品单价"].str.split('¥', expand=True)[1].astype("int")
df.head(3)
订单编号 | 订单日期 | 数量 | 产品名称 | 产品类型 | 产品描述 | 产品单价 | 单价 | |
---|---|---|---|---|---|---|---|---|
0 | 1 | 2020-07-06 | 10 | 中性笔 | 文具 | 0.5规格中性笔 | ¥1 | 1 |
1 | 1 | 2020-07-06 | 2 | 透明胶 | 办公用品 | NaN | ¥3 | 3 |
2 | 1 | 2020-07-06 | 3 | 裁纸刀 | 办公用品 | NaN | ¥5 | 5 |
方法二:使用extract
Series.str.extract(pat, flags=0, expand=True)
pat:具有捕获组的正则表达式模式,flags:int,默认值为0(无标志),expand:True输出Dataframe,False输出Series。
df.loc[:,"单价"] = df.loc[:,"产品单价"].str.extract('((?<=¥).*)', expand=False).astype("int")
df.head(3)
订单编号 | 订单日期 | 数量 | 产品名称 | 产品类型 | 产品描述 | 产品单价 | 单价 | |
---|---|---|---|---|---|---|---|---|
0 | 1 | 2020-07-06 | 10 | 中性笔 | 文具 | 0.5规格中性笔 | ¥1 | 1 |
1 | 1 | 2020-07-06 | 2 | 透明胶 | 办公用品 | NaN | ¥3 | 3 |
2 | 1 | 2020-07-06 | 3 | 裁纸刀 | 办公用品 | NaN | ¥5 | 5 |
DataFrame合并主要使用两种方法,merge与concat
df1 = pd.DataFrame({"name":['zhangs', 'lisi', 'wangwu', 'zhaoliu'], "score":[80,75,90,70], "class":[1,1,2,3]})
df2 = pd.DataFrame({"name":['zhangs', 'lisi', 'linji', 'zhoujl'], "age":[15,14,34,39], "gender":[0,0,1,1]})
df1
name | score | class | |
---|---|---|---|
0 | zhangs | 80 | 1 |
1 | lisi | 75 | 1 |
2 | wangwu | 90 | 2 |
3 | zhaoliu | 70 | 3 |
df2
name | age | gender | |
---|---|---|---|
0 | zhangs | 15 | 0 |
1 | lisi | 14 | 0 |
2 | linji | 34 | 1 |
3 | zhoujl | 39 | 1 |
提供了类似于SQL数据库连接操作的功能,支持左联、右联、内联和外联等全部四种SQL连接操作类型
DataFrame.merge(right, how='inner', on=None, left_on=None, right_on=None,
left_index=False, right_index=False, sort=False, suffixes=('_x', '_y'),
copy=True, indicator=False, validate=None)
参数 | 说明 |
---|---|
left | 参与合并的左侧DataFrame |
right | 参与合并的右侧DataFrame |
how | 连接方式:‘inner’(默认);还有,‘outer’、‘left’、‘right’ |
on | 用于连接的列名,必须同时存在于左右两个DataFrame对象中,如果未指定,则以left和right列名的交集作为连接键 |
left_on | 左侧DataFarme中用作连接键的列 |
right_on | 右侧DataFarme中用作连接键的列 |
left_index | 将左侧的行索引用作其连接键 |
right_index | 将右侧的行索引用作其连接键 |
sort | 根据连接键对合并后的数据进行排序,默认为True。有时在处理大数据集时,禁用该选项可获得更好的性能 |
suffixes | 字符串值元组,用于追加到重叠列名的末尾,默认为(‘_x’,‘_y’).例如,左右两个DataFrame对象都有‘data’,则结果中就会出现‘data_x’,‘data_y’ |
copy | 设置为False,可以在某些特殊情况下避免将数据复制到结果数据结构中。默认总是赋值 |
使用:
# 方法一
df1.merge(df2)
# 方法二
df3 = pd.merge(df1,df2)
内连接(inner默认)基于共同列的交集进行连接
df3 = pd.merge(df1,df2,on='name')
df3
name | score | class | age | gender | |
---|---|---|---|---|---|
0 | zhangs | 80 | 1 | 15 | 0 |
1 | lisi | 75 | 1 | 14 | 0 |
外连接(outer)基于共同列的并集进行连接
df3 = pd.merge(df1,df2,how='outer',on='name')
df3
name | score | class | age | gender | |
---|---|---|---|---|---|
0 | zhangs | 80.0 | 1.0 | 15.0 | 0.0 |
1 | lisi | 75.0 | 1.0 | 14.0 | 0.0 |
2 | wangwu | 90.0 | 2.0 | NaN | NaN |
3 | zhaoliu | 70.0 | 3.0 | NaN | NaN |
4 | linji | NaN | NaN | 34.0 | 1.0 |
5 | zhoujl | NaN | NaN | 39.0 | 1.0 |
左连接(left)基于左边位置dataframe的列进行连接
df3 = pd.merge(df1,df2,how='left',on='name')
df3
name | score | class | age | gender | |
---|---|---|---|---|---|
0 | zhangs | 80 | 1 | 15.0 | 0.0 |
1 | lisi | 75 | 1 | 14.0 | 0.0 |
2 | wangwu | 90 | 2 | NaN | NaN |
3 | zhaoliu | 70 | 3 | NaN | NaN |
右连接(right)基于右边位置dataframe的列进行连接
df3 = pd.merge(df1,df2,how='right',on='name')
df3
name | score | class | age | gender | |
---|---|---|---|---|---|
0 | zhangs | 80.0 | 1.0 | 15 | 0 |
1 | lisi | 75.0 | 1.0 | 14 | 0 |
2 | linji | NaN | NaN | 34 | 1 |
3 | zhoujl | NaN | NaN | 39 | 1 |
提供了axis设置可用于df间行方向(增加行,下同)或列方向(增加列,下同)进行内联或外联拼接操作
pandas.concat(objs, axis=0, join='outer', ignore_index=False, keys=None,
levels=None, names=None, verify_integrity=False, sort=False, copy=True)
参数 | 默认 | 说明 |
---|---|---|
objs | 必填 | 参与连接的列表或字典,且列表或字典里的对象是pandas数据类型,唯一必须给定的参数 |
axis=0 | 0 | 指明连接的轴向,0是纵轴,1是横轴 |
join | ‘outer’ | ‘inner’(交集),‘outer’(并集),指明轴向索引的索引是交集还是并集 |
ignore_index | False | 不保留连接轴上的索引,产生一组新索引range(total_length) |
keys | None | 与连接对象有关的值,用于形成连接轴向上的层次化索引(外层索引),可以是任意值的列表或数组、元组数据、数组列表(如果将levels设置成多级数组的话) |
levels | None | 指定用作层次化索引各级别(内层索引)上的索引,如果设置keys的话 |
names | None | 用于创建分层级别的名称,如果设置keys或levels的话 |
verify_integrity | False | 检查结果对象新轴上的重复情况,如果发横则引发异常,允许重复 |
sort | False | 根据连接键对合并后的数据进行排序。有时在处理大数据集时,禁用该选项可获得更好的性能 |
copy | True | 默认True时是深拷贝,False时为浅拷贝 |
行拼接
pd.concat([df1,df2], ignore_index=True, sort=False)
name | score | class | age | gender | |
---|---|---|---|---|---|
0 | zhangs | 80.0 | 1.0 | NaN | NaN |
1 | lisi | 75.0 | 1.0 | NaN | NaN |
2 | wangwu | 90.0 | 2.0 | NaN | NaN |
3 | zhaoliu | 70.0 | 3.0 | NaN | NaN |
4 | zhangs | NaN | NaN | 15.0 | 0.0 |
5 | lisi | NaN | NaN | 14.0 | 0.0 |
6 | linji | NaN | NaN | 34.0 | 1.0 |
7 | zhoujl | NaN | NaN | 39.0 | 1.0 |
列拼接
pd.concat([df1,df2], axis=1, sort=False)
name | score | class | name | age | gender | |
---|---|---|---|---|---|---|
0 | zhangs | 80 | 1 | zhangs | 15 | 0 |
1 | lisi | 75 | 1 | lisi | 14 | 0 |
2 | wangwu | 90 | 2 | linji | 34 | 1 |
3 | zhaoliu | 70 | 3 | zhoujl | 39 | 1 |
df = pd.DataFrame({"商品":["中性笔","透明胶", "裁纸刀" ,"橡皮擦"], "零售价":[5,8,6,4], "本月销量":[47,59,64,37], "上月销量":[48,95,34,16]})
print("示例数据:")
df
示例数据:
商品 | 零售价 | 本月销量 | 上月销量 | |
---|---|---|---|---|
0 | 中性笔 | 5 | 47 | 48 |
1 | 透明胶 | 8 | 59 | 95 |
2 | 裁纸刀 | 6 | 64 | 34 |
3 | 橡皮擦 | 4 | 37 | 16 |
# 单列计算:团购价 = 零售价 - 1
df.loc[:, '团购价'] = df.loc[:, '零售价'].map(lambda x: x-1)
# 多列计算
## 加法:总销量=本月销量+上月销量
df.loc[:,"总销量"] = df.loc[:,"本月销量"] + df.loc[:,"上月销量"]
## 减法:销售差=本月销量-上月销量
df.loc[:,"销售差"] = df.loc[:,"本月销量"] - df.loc[:,"上月销量"]
## 乘法:本月销售额 = 本月销量*零售价
df.loc[:,"本月销售额"] = df.loc[:,"本月销量"] * df.loc[:,"零售价"]
## 除法:本月销售额占比 = 本月销量/总销量
df.loc[:,"本月销售额占比"] = df.loc[:,"本月销量"] / df.loc[:,"总销量"]
df
商品 | 零售价 | 本月销量 | 上月销量 | 团购价 | 总销量 | 销售差 | 本月销售额 | 本月销售额占比 | |
---|---|---|---|---|---|---|---|---|---|
0 | 中性笔 | 5 | 47 | 48 | 4 | 95 | -1 | 235 | 0.494737 |
1 | 透明胶 | 8 | 59 | 95 | 7 | 154 | -36 | 472 | 0.383117 |
2 | 裁纸刀 | 6 | 64 | 34 | 5 | 98 | 30 | 384 | 0.653061 |
3 | 橡皮擦 | 4 | 37 | 16 | 3 | 53 | 21 | 148 | 0.698113 |
数据分组通过groupby函数实现
实现类似SQL聚合函数的运算通过agg,transform和apply实现
apply虽然灵活,但比agg,transform慢,能用agg,transform解决就用。
agg:聚合函数,聚合函数操作始终是在轴(默认是列轴,也可设置行轴)上执行 DataFrame.agg(func, axis=0, * args, ** kwargs)
func:传入聚合函数作用于每一列或行
axis:0,每一列;1,每一行
写法:DataFrame.agg([‘sum’, “max”]) or DataFrame.agg(‘sum’) or DataFrame.agg(np.sum)
transform:与agg不同的是,transform会在每个对应位置上返回结果,结果长度与原df长度一样
apply:自动遍历整个 Series 或者 DataFrame, 对每一个元素运行指定的函数
DataFrame.apply(func, axis=0, broadcast=None, raw=False, reduce=None, result_type=None, args=(), **kwds)
func:function作用于每一列或行,可传入任意函数
axis:0,每一列;1,每一行
result_type:{‘expand’, ‘reduce’, ‘broadcast’, None} 默认 None
expand:类似列表的结果将转换为列
reduce:返回Series
broadcast:结果将广播到DataFrame的原始形状,保留原始索引和列 raw:默认False,传递Series;True,传递ndarray
不推荐使用以下参数,推荐使用result_type:
broadcast:广播,仅与聚合函数有关。False or None,返回一个Series;True,在原本DataFrame上添加一列
reduce:默认None,系统自动判断返回值;True,返回Series;False,返回DataFrame
聚合函数 | numpy | 用途 |
---|---|---|
min | np.min | 最小值 |
max | np.max | 最大值 |
sum | np.sum | 求和 |
mean | np.mean | 平均值 |
median | np.median | 中位数 |
std | np.std | 标准差 |
var | np.var | 方差 |
count | np.count | 计数 |
prod | np.prod | 累积 |
NaN | np.power | 幂运算 |
NaN | np.sqrt | 开方 |
NaN | np.argmin | 最小值下标 |
NaN | np.argmax | 最大值下标 |
NaN | np.inf | 无穷大 |
NaN | np.exp(10) | 以e为底的指数 |
NaN | np.log(10) | 对数 |
df = pd.read_excel(".\data_excel.xlsx")
print("示例数据:")
df.head()
示例数据:
订单编号 | 订单日期 | 数量 | 产品名称 | 产品类型 | 产品描述 | 产品单价 | |
---|---|---|---|---|---|---|---|
0 | 1 | 2020-07-06 | 10 | 中性笔 | 文具 | 0.5规格中性笔 | ¥1 |
1 | 1 | 2020-07-06 | 2 | 透明胶 | 办公用品 | NaN | ¥3 |
2 | 1 | 2020-07-06 | 3 | 裁纸刀 | 办公用品 | NaN | ¥5 |
3 | 2 | 2020-07-06 | 3 | 中性笔 | 文具 | NaN | ¥1 |
4 | 2 | 2020-07-06 | 1 | 橡皮擦 | 文具 | NaN | ¥3 |
groupby的过程就是将原有的DataFrame按照groupby的字段,划分为若干个分组DataFrame
由于返回值是一个DataFrameGroupBy对象,返回的结果是其内存地址,并不利于直观地理解,转为list可查看。
单列分组
list(df.groupby('订单日期'))
[(Timestamp('2020-07-06 00:00:00'),
订单编号 订单日期 数量 产品名称 产品类型 产品描述 产品单价
0 1 2020-07-06 10 中性笔 文具 0.5规格中性笔 ¥1
1 1 2020-07-06 2 透明胶 办公用品 NaN ¥3
2 1 2020-07-06 3 裁纸刀 办公用品 NaN ¥5
3 2 2020-07-06 3 中性笔 文具 NaN ¥1
4 2 2020-07-06 1 橡皮擦 文具 NaN ¥3
5 2 2020-07-06 2 铅笔 文具 NaN ¥1
6 2 2020-07-06 2 作业本 文具 NaN ¥1
7 3 2020-07-06 2 婴儿尿片 婴儿用品 包 ¥100
8 3 2020-07-06 10 青岛啤酒 饮料 罐装 ¥5),
(Timestamp('2020-07-15 00:00:00'),
订单编号 订单日期 数量 产品名称 产品类型 产品描述 产品单价
9 4 2020-07-15 5 勇闯天涯啤酒 饮料 罐装 ¥5
10 4 2020-07-15 10 可乐 饮料 罐装 ¥5
11 5 2020-07-15 5 雪碧 饮料 罐装 ¥4
12 6 2020-07-15 2 透明胶 办公用品 NaN ¥3
13 6 2020-07-15 3 裁纸刀 办公用品 NaN ¥5
14 6 2020-07-15 4 502胶水 办公用品 NaN ¥5
15 6 2020-07-15 5 AB胶水 办公用品 NaN ¥6
16 7 2020-07-15 1 儿童背包 文具 NaN ¥50
17 7 2020-07-15 1 文具盒 文具 NaN ¥20
18 8 2020-07-15 1 橡皮擦 文具 NaN ¥3
19 8 2020-07-15 2 铅笔 文具 NaN ¥1
20 8 2020-07-15 2 作业本 文具 NaN ¥1
21 8 2020-07-15 2 婴儿尿片 婴儿用品 包 ¥100),
(Timestamp('2020-08-15 00:00:00'),
订单编号 订单日期 数量 产品名称 产品类型 产品描述 产品单价
22 9 2020-08-15 10 青岛啤酒 饮料 罐装 ¥5
23 9 2020-08-15 5 勇闯天涯啤酒 饮料 罐装 ¥5
24 9 2020-08-15 10 可乐 饮料 罐装 ¥5
25 9 2020-08-15 5 雪碧 饮料 罐装 ¥4
26 9 2020-08-15 2 透明胶 办公用品 NaN ¥3
27 10 2020-08-15 3 裁纸刀 办公用品 NaN ¥5
28 10 2020-08-15 4 502胶水 办公用品 NaN ¥5
29 10 2020-08-15 5 AB胶水 办公用品 NaN ¥6
30 11 2020-08-15 1 儿童背包 文具 NaN ¥50
31 11 2020-08-15 1 文具盒 文具 NaN ¥20)]
多列分组
list(df.groupby(['订单日期', '产品类型']))
[((Timestamp('2020-07-06 00:00:00'), '办公用品'),
订单编号 订单日期 数量 产品名称 产品类型 产品描述 产品单价 产品总销量
1 1 2020-07-06 2 透明胶 办公用品 NaN ¥3 6
2 1 2020-07-06 3 裁纸刀 办公用品 NaN ¥5 9),
((Timestamp('2020-07-06 00:00:00'), '婴儿用品'),
订单编号 订单日期 数量 产品名称 产品类型 产品描述 产品单价 产品总销量
7 3 2020-07-06 2 婴儿尿片 婴儿用品 包 ¥100 4),
((Timestamp('2020-07-06 00:00:00'), '文具'),
订单编号 订单日期 数量 产品名称 产品类型 产品描述 产品单价 产品总销量
0 1 2020-07-06 10 中性笔 文具 0.5规格中性笔 ¥1 13
3 2 2020-07-06 3 中性笔 文具 NaN ¥1 13
4 2 2020-07-06 1 橡皮擦 文具 NaN ¥3 2
5 2 2020-07-06 2 铅笔 文具 NaN ¥1 4
6 2 2020-07-06 2 作业本 文具 NaN ¥1 4),
((Timestamp('2020-07-06 00:00:00'), '饮料'),
订单编号 订单日期 数量 产品名称 产品类型 产品描述 产品单价 产品总销量
8 3 2020-07-06 10 青岛啤酒 饮料 罐装 ¥5 20),
((Timestamp('2020-07-15 00:00:00'), '办公用品'),
订单编号 订单日期 数量 产品名称 产品类型 产品描述 产品单价 产品总销量
12 6 2020-07-15 2 透明胶 办公用品 NaN ¥3 6
13 6 2020-07-15 3 裁纸刀 办公用品 NaN ¥5 9
14 6 2020-07-15 4 502胶水 办公用品 NaN ¥5 8
15 6 2020-07-15 5 AB胶水 办公用品 NaN ¥6 10),
((Timestamp('2020-07-15 00:00:00'), '婴儿用品'),
订单编号 订单日期 数量 产品名称 产品类型 产品描述 产品单价 产品总销量
21 8 2020-07-15 2 婴儿尿片 婴儿用品 包 ¥100 4),
((Timestamp('2020-07-15 00:00:00'), '文具'),
订单编号 订单日期 数量 产品名称 产品类型 产品描述 产品单价 产品总销量
16 7 2020-07-15 1 儿童背包 文具 NaN ¥50 2
17 7 2020-07-15 1 文具盒 文具 NaN ¥20 2
18 8 2020-07-15 1 橡皮擦 文具 NaN ¥3 2
19 8 2020-07-15 2 铅笔 文具 NaN ¥1 4
20 8 2020-07-15 2 作业本 文具 NaN ¥1 4),
((Timestamp('2020-07-15 00:00:00'), '饮料'),
订单编号 订单日期 数量 产品名称 产品类型 产品描述 产品单价 产品总销量
9 4 2020-07-15 5 勇闯天涯啤酒 饮料 罐装 ¥5 10
10 4 2020-07-15 10 可乐 饮料 罐装 ¥5 20
11 5 2020-07-15 5 雪碧 饮料 罐装 ¥4 10),
((Timestamp('2020-08-15 00:00:00'), '办公用品'),
订单编号 订单日期 数量 产品名称 产品类型 产品描述 产品单价 产品总销量
26 9 2020-08-15 2 透明胶 办公用品 NaN ¥3 6
27 10 2020-08-15 3 裁纸刀 办公用品 NaN ¥5 9
28 10 2020-08-15 4 502胶水 办公用品 NaN ¥5 8
29 10 2020-08-15 5 AB胶水 办公用品 NaN ¥6 10),
((Timestamp('2020-08-15 00:00:00'), '文具'),
订单编号 订单日期 数量 产品名称 产品类型 产品描述 产品单价 产品总销量
30 11 2020-08-15 1 儿童背包 文具 NaN ¥50 2
31 11 2020-08-15 1 文具盒 文具 NaN ¥20 2),
((Timestamp('2020-08-15 00:00:00'), '饮料'),
订单编号 订单日期 数量 产品名称 产品类型 产品描述 产品单价 产品总销量
22 9 2020-08-15 10 青岛啤酒 饮料 罐装 ¥5 20
23 9 2020-08-15 5 勇闯天涯啤酒 饮料 罐装 ¥5 10
24 9 2020-08-15 10 可乐 饮料 罐装 ¥5 20
25 9 2020-08-15 5 雪碧 饮料 罐装 ¥4 10)]
统计不同产品的总销量,使用agg与apply
df.groupby('产品名称')['数量'].agg('sum').index
Index(['502胶水', 'AB胶水', '中性笔', '作业本', '儿童背包', '勇闯天涯啤酒', '可乐', '婴儿尿片', '文具盒',
'橡皮擦', '裁纸刀', '透明胶', '铅笔', '雪碧', '青岛啤酒'],
dtype='object', name='产品名称')
df.groupby('产品名称')['数量'].agg('sum')
# 同df.groupby('产品名称')['数量'].apply(lambda x:x.sum())
# 同df.groupby('产品名称')['数量'].apply(np.sum)
产品名称
502胶水 8
AB胶水 10
中性笔 13
作业本 4
儿童背包 2
勇闯天涯啤酒 10
可乐 20
婴儿尿片 4
文具盒 2
橡皮擦 2
裁纸刀 9
透明胶 6
铅笔 4
雪碧 10
青岛啤酒 20
Name: 数量, dtype: int64
将总销量添加到对应商品上,使用transform
df['产品总销量'] = df.groupby('产品名称')['数量'].transform('sum')
df.head()
订单编号 | 订单日期 | 数量 | 产品名称 | 产品类型 | 产品描述 | 产品单价 | 产品总销量 | |
---|---|---|---|---|---|---|---|---|
0 | 1 | 2020-07-06 | 10 | 中性笔 | 文具 | 0.5规格中性笔 | ¥1 | 13 |
1 | 1 | 2020-07-06 | 2 | 透明胶 | 办公用品 | NaN | ¥3 | 6 |
2 | 1 | 2020-07-06 | 3 | 裁纸刀 | 办公用品 | NaN | ¥5 | 9 |
3 | 2 | 2020-07-06 | 3 | 中性笔 | 文具 | NaN | ¥1 | 13 |
4 | 2 | 2020-07-06 | 1 | 橡皮擦 | 文具 | NaN | ¥3 | 2 |
多列分组:输出不同订单日期不同商品的销售总量
df.groupby(['订单日期', '产品类型'])['产品总销量'].agg('sum')
订单日期 产品类型
2020-07-06 办公用品 15
婴儿用品 4
文具 36
饮料 20
2020-07-15 办公用品 33
婴儿用品 4
文具 14
饮料 40
2020-08-15 办公用品 33
文具 4
饮料 60
Name: 产品总销量, dtype: int64