数据分析_表和表的运用

Kobe

kobe_df = pd.read_csv('data/Kobe_data.csv', index_col='shot_id')
# 1. 科比使用得最多的投篮动作
ser = kobe_df.action_type + '-' + kobe_df.combined_shot_type
ser.value_counts().index[0]
# ser.mode()[0]
# ser.describe()['top']
# 2. 科比交手次数最多的队伍
kobe_df.drop_duplicates('game_id').opponent.value_counts().index[0]
# kobe_df.drop_duplicates('game_id').opponent.mode()[0]
# kobe_df.drop_duplicates('game_id').opponent.describe()['top']
# 3. 职业生涯总得分
# 先将shot_made_flag列的空值进行填充,再来筛选数据
kobe_df['shot_made_flag'] = kobe_df.shot_made_flag.fillna(0).map(int)
temp = kobe_df[kobe_df.shot_made_flag == 1].shot_type
# temp.apply(lambda x: int(x[0])).sum()
# 获取对应的字符串向量 ---> 通过正则表达式捕获组语法抽取数字
temp.str.extract(r'(\d+)')[0].map(int).sum()

hrs

import pymysql

conn = pymysql.connect(host='47.104.31.138', port=3306,
                       user='guest', password='Guest.618',
                       database='hrs', charset='utf8mb4')
dept_df = pd.read_sql('select dno, dname, dloc from tb_dept', conn)
dept_df
emp_df = pd.read_sql(
    sql='select eno, ename, job, mgr, sal, comm, dno from tb_emp', 
    con=conn,
    # index_col='eno'
)
连接两表/按条件查询
# 连接两表
pd.merge(emp_df, dept_df, how='inner', on='dno').set_index('eno')
# 按条件查询
emp_df[(emp_df.dno == 20) & (emp_df.sal >= 5000)]
#	eno	ename	job	mgr	sal	comm	dno
#1	2056	乔峰	分析师	7800.0	5000	1500.0	20
#13	7800	张三丰	总裁	NaN	9000	1200.0	20
emp_df.query('dno == 20 and sal >= 5000')
删除行/列
# 删除行
emp_df.drop(index=emp_df[emp_df.dno != 20].index, inplace=True)
# 删除列
emp_df.drop(columns=['mgr', 'dno'], inplace=True)

修改索引
# 修改索引
# 修改行或者列的索引
emp_df.rename(columns={'sal': 'salary', 'comm': 'allowance'}, inplace=True)

重置索引/设置索引
# 重置索引(将原来的索引列变成普通列)
emp_df.reset_index(inplace=True)

# 设置索引(指定一个列或多个列充当索引)
emp_df.set_index('ename', inplace=True)
emp_df

# 调整索引(的顺序)
emp_df.reindex(columns=['salary', 'job'])
#	salary	job
#ename		
#乔峰	     5000	分析师
#李莫愁	3500	设计师
#张无忌	3200	程序员
#丘处机	3400	程序员
#欧阳锋	3200	程序员
#张翠山	4000	程序员
#张三丰	9000	总裁

emp_df.reindex(index=['李莫愁', '张三丰', '乔峰'])
#	index	eno	job	salary	allowance
#ename					
#李莫愁	2	3088	设计师	3500	800.0
#张三丰	13	7800	总裁	9000	1200.0
#乔峰	1	2056	分析师	5000	1500.0

笛卡尔积

import itertools

names = ['高新', '犀浦', '新津']
years = ['2018', '2019']
groups = ['A', 'B']
# 笛卡尔积
for name, year, group in itertools.product(names, years, groups):
    print(name, year, group)
# 高新 2018 A
# 高新 2018 B
# 高新 2019 A
# 高新 2019 B
# 犀浦 2018 A
# 犀浦 2018 B
# 犀浦 2019 A
# 犀浦 2019 B
# 新津 2018 A
# 新津 2018 B
# 新津 2019 A
# 新津 2019 B

汇总两个表

import itertools

names = ['高新', '犀浦', '新津']
years = ['2018', '2019']
dfs = [pd.read_excel(f'data/小宝剑大药房({name}店){year}年销售数据.xlsx', header=1) 
       for name, year in itertools.product(names, years)]
# dfs = []
# for name in names:
#     temp_df = pd.read_excel(f'data/小宝剑大药房({name}店)2018年销售数据.xlsx', header=1)
#     dfs.append(temp_df)
# pd.concat(dfs).reset_index(drop=True)
pd.concat(dfs, ignore_index=True).to_excel('小宝剑大药房2018-2019年汇总数据.xlsx')

看表的空值

emp_df.isnull()
# 	index	eno	job	salary	allowance
# ename					
# 乔峰	False	False	False	False	False
# 李莫愁	False	False	False	False	False
# 张无忌	False	False	False	False	True
# 丘处机	False	False	False	False	True
# 欧阳锋	False	False	False	False	True
# 张翠山	False	False	False	False	True
# 张三丰	False	False	False	False	False

看表的尾/首的xx条数据

youtube_df.tail(10)
youtube_df.head(10)

对表里某列做判断

youtube_df.duplicated('video_id')
# 0        False
# 1        False
# 2        False
# 3        False
# 4        False

对表里某列去重

# 去重
youtube_df = youtube_df.drop_duplicates('video_id', keep='first')
youtube_df

修改表里某个字段

emp_df.replace('程序员', '程序猿', inplace=True)

往表里添加某个元素

Get value at specified row/column pair
>>> df.at[4, 'B']
2
Set value at specified row/column pair

>>> df.at[4, 'B'] = 10
>>> df.at[4, 'B']
10
emp_df.at[2, 'job'] = '程序媛'
# 张三丰	13.0	7800.0	总裁	9000.0	1200.0
# 2	NaN	NaN	程序媛	NaN	NaN

表的正则表达式

# 把表里的所有程序媛和程序猿替换成程序员
emp_df.replace(regex='程序[猿媛]', value='程序员')
# 把表里job列的程序猿/媛换成程序员
emp_df['job'] = emp_df.job.str.replace('程序[猿媛]', '程序员', regex=True)

apply 和transform

temp = pd.DataFrame({'A': range(3), 'B': range(1, 4)})
# 	A	B
# 0	0	1
# 1	1	2
# 2	2	3
temp.apply(np.sqrt)
# 	A	B
# 0	0.000000	1.000000
# 1	1.000000	1.414214
# 2	1.414214	1.732051
temp.apply(np.sum)
# A    3
# B    6
# dtype: int64

# 沿1轴求和
temp.apply(np.sum, axis=1)
# 0    1
# 1    3
# 2    5
# dtype: int64
temp.transform(np.sqrt)
# A	B
# 0	0.000000	1.000000
# 1	1.000000	1.414214
# 2	1.414214	1.732051
temp.transform([np.exp, np.sqrt])
# 	A	B
# exp	sqrt	exp	sqrt
# 0	1.000000	0.000000	2.718282	1.000000
# 1	2.718282	1.000000	7.389056	1.414214
# 2	7.389056	1.414214	20.085537	1.732051
# 将性别字段处理成“男”和“女”
student_df['stu_sex'] = student_df.stu_sex.transform(lambda x: '男' if x == 1 else '女')
student_df

表的排序

# 根据点赞数和播放数对视频进行排序
temp = youtube_df.sort_values(by=['likes', 'views'], ascending=[False, True])

# 找出点赞数的前10名
youtube_df.drop_duplicates('video_id', keep='last').nlargest(10, 'likes')

添加新列

youtube_df['hot_value'] = youtube_df.views + youtube_df.likes + youtube_df.dislikes + youtube_df.comment_count

表的分组

# 数据透视 ---> 分组聚合 ---> SAC(Split - Aggregate - Combine)
# 根据频道对视频分组,计算每个频道热度值的和
youtube_df.groupby(by='channel_title').hot_value.sum()

def ptp(g):
    return g.max() - g.min()


# 根据频道对视频分组,计算每个频道热度值和点赞数的和、最大值、最小值和极差
temp = youtube_df.groupby(by='channel_title')
temp[['hot_value', 'likes']].agg(['sum', 'max', 'min', ptp])

表的求和和分组

student_df.stu_sex.value_counts()
# 男    7
# 女    3
# Name: stusex, dtype: int64

student_df.groupby('stu_sex').count()
# stu_id	stu_name	stu_birth	stu_addr	col_id
# stu_sex					
# 女	3	3	3	3	3
# 男	7	7	7	5	7

temp = student_df.groupby(by=['collid', 'stusex']).count()
# 		           stuid  stuname  stubirth	stuaddr
# collid	stusex				
# 1	           女	2	2	2	2
#              男	4	4	4	4
# 2	           男	1	1	1	1
# 3	           女	1	1	1	1
#              男	2	2	2	2

按多个分类

temp.loc[(1, '男')]
# stuid       4
# stuname     4
# stubirth    4
# stuaddr     4
# Name: (1, 男), dtype: int64

透视表

# 生成透视表(根据性别统计人数)
student_df.pivot_table(index='stu_sex', values='stu_id', aggfunc='count')
# 	       stu_id
# stu_sex	
# 女	         3
# 男	         7
# 生成透视表(根据学院和性别统计人数)
student_df.pivot_table(index=['col_id', 'stu_sex'], values='stuid', aggfunc='count')
# 		            stu_id
# col_id	stu_sex	
#      1	女	     2
#           男	     4
#      2	男	     1
#      3	女	     1
#           男	     2
temp = student_df.pivot_table(
    index='col_id', 
    columns='stu_sex', 
    values='stu_id', 
    aggfunc='count',
    fill_value=0
)
# stu_sex	女	男
# col_id		
#      1	2	4
#      2	0	1
#      3	1	2

卖手机

df1 = pd.DataFrame({
    "类别": ["手机", "手机", "手机", "手机", "手机", "电脑", "电脑", "电脑", "电脑"],
    "品牌": ["华为", "华为", "华为", "小米", "小米", "华为", "华为", "小米", "小米"],
    "等级": ["A类", "B类", "A类", "B类", "C类", "A类", "B类", "C类", "A类"],
    "A组": [1, 2, 2, 3, 3, 4, 5, 6, 7],
    "B组": [2, 4, 5, 5, 6, 6, 8, 9, 9]
})
# 	类别	品牌	等级	A组	B组
# 0	手机	华为	A类	1	2
# 1	手机	华为	B类	2	4
# 2	手机	华为	A类	2	5
# 3	手机	小米	B类	3	5
# 4	手机	小米	C类	3	6
# 5	电脑	华为	A类	4	6
# 6	电脑	华为	B类	5	8
# 7	电脑	小米	C类	6	9
# 8	电脑	小米	A类	7	9
# 任务1:A组手机和电脑各卖出多少台
df1.pivot_table(index='类别', values='A组', aggfunc=np.sum)
#        A组
# 类别	
# 手机	11
# 电脑	22
# 任务2:A组不同品牌的手机和电脑各卖出多少台
df1.pivot_table(index='类别', columns='品牌', values='A组', aggfunc=np.sum)
# 品牌	华为	小米
# 类别		
# 手机	5	6
# 电脑	9	13
# 任务3:不同品牌的手机和电脑,A组和B组各卖出多少台
df1.pivot_table(index=['类别', '品牌'], values=['A组', 'B组'], aggfunc=np.sum)
#                A组	  B组
# 类别	品牌		
# 手机	华为	   5	11
#         小米	6	 11
# 电脑	华为	   9	14
#         小米	13	 18

卖水果

df2 = pd.DataFrame({
    '类别': ['水果', '水果', '水果', '蔬菜', '蔬菜', '肉类', '肉类'],
    '产地': ['美国', '中国', '中国', '中国', '新西兰', '新西兰', '美国'],
    '名称': ['苹果', '梨', '草莓', '番茄', '黄瓜', '羊肉', '牛肉'],
    '数量': [5, 5, 9, 3, 2, 10, 8],
    '价格': [5.8, 5.2, 10.8, 3.5, 3.0, 13.1, 20.5]
})
# 	类别	产地	名称	数量	价格
# 0	水果	美国	苹果	5	5.8
# 1	水果	中国	梨	5	5.2
# 2	水果	中国	草莓	9	10.8
# 3	蔬菜	中国	番茄	3	3.5
# 4	蔬菜	新西兰	黄瓜	2	3.0
# 5	肉类	新西兰	羊肉	10	13.1
# 6	肉类	美国	牛肉	8	20.5
# 交叉表:一种特殊的透视表,可以用不同的表(维度表、事实表)中的数据进行数据透视
pd.crosstab(
    index=df2['类别'], 
    columns=df2['产地'], 
    values=df2['数量'], 
    aggfunc=np.sum,
    margins=True,
    margins_name='总计'
).fillna(0).applymap(int)
# 产地	中国	新西兰	美国	总计
# 类别				
# 水果	14	0	5	19
# 肉类	0	10	8	18
# 蔬菜	3	2	0	5
# 总计	17	12	13	42

np.random.normal(μ,σ,(n,m))

形成一个元素来自均值是μ,方差为σ正态分布,n行m列的数组

数据的分箱操作

heights = np.round(np.random.normal(172, 8, 500), 1)
temp_df = pd.DataFrame(data=heights, index=np.arange(1001, 1501), columns=['身高'])
# 如果分组用的数据不是离散型的数据,那么就需要先对数据进行分箱(离散化)
bins = [0, 150, 160, 170, 180, 190, 200, np.inf]
# 使用cut函数对数据分箱,将分箱的结果作为groupby操作的分组依据
cate = pd.cut(temp_df['身高'], bins, right=False)
result = temp_df.groupby(cate).count()

作业:2018年北京积分落户数据分析。

  1. 根据company将落户人员分组,统计每个公司有多少积分落户人员?
  2. 根据年龄将落户人员分组,统计每个年龄段有多少人(建议5岁一个年龄段)?
  3. 根据落户积分将落户人员分组,统计每个积分段有多少人?
luohu_df = pd.read_csv('data/2018年北京积分落户数据.csv', index_col='id')
pd.to_datetime(luohu_df.birthday)
# id
# 1      1972-12-01
# 2      1974-12-01
# 3      1974-05-01
# 4      1975-07-01
# 5      1974-11-01
# 将生日换算成年龄
from datetime import datetime

ref_date = datetime(2018, 7, 1)
ser = ref_date - pd.to_datetime(luohu_df.birthday)
luohu_df['age'] = ser.dt.days // 365
luohu_df
# 	 name	birthday	company	score	age
# id					
# 1	 杨效丰	1972-12	北京利德华福电气技术有限公司	122.59	45
# 2	 纪丰伟	1974-12	北京航天数据股份有限公司	121.25	43
# 3	  王永	1974-05	品牌联盟(北京)咨询股份公司	118.96	44
# 根据company将落户人员分组,统计每个公司有多少积分落户人员?
temp = luohu_df.company.value_counts()
temp[temp > 20]
# 北京华为数字技术有限公司        137
# 中央电视台                73
# 北京首钢建设集团有限公司         57
# 百度在线网络技术(北京)有限公司     55
# 联想(北京)有限公司           48
# 中国民生银行股份有限公司         40
# 北京外企人力资源服务有限公司       39
# 国际商业机器(中国)投资有限公司     39
# 中国国际技术智力合作有限公司       29
# 华为技术有限公司北京研究所        27
# 爱立信(中国)通信有限公司        26
# 腾讯科技(北京)有限公司         24
# 北京阿里巴巴云计算技术有限公司      23
# 根据年龄将落户人员分组,统计每个年龄段有多少人(建议5岁一个年龄段)?
bins = np.arange(30, 61, 5)
cate = pd.cut(luohu_df.age, bins)
temp = luohu_df.groupby(cate).name.count()
temp.plot(kind='bar')
for i in range(temp.size):
    plt.text(i, temp[i], temp[i], ha='center')
plt.xticks(
    np.arange(temp.size), 
    labels=[f'{index.left}~{index.right}岁' for index in temp.index], 
    rotation=30
)
plt.show()
# 根据落户积分将落户人员分组,统计每个积分段有多少人?
bins = np.arange(90, 126, 5)
cate = pd.cut(luohu_df.score, bins, right=False)
luohu_df.groupby(cate).name.count()
# score
# [90, 95)      3319
# [95, 100)     1771
# [100, 105)     662
# [105, 110)     219
# [110, 115)      33
# [115, 120)      13
# [120, 125)       2
# Name: name, dtype: int64

拉钩招聘分析

  1. 数据清洗:找出“数据分析”岗位(positionName)的数据,并将薪资(salary)范围处理成中间值。

  2. 数据分析:找出各大城市(city)数据分析岗位的需求量并绘制柱状图。

  3. 数据分析:找出不同领域(industryField)对数据分析方位的需求量的占比并绘制饼图。

  4. 数据分析:分析各城市的薪资水平并绘制折线图

lagou_df = pd.read_csv(
    'data/lagou.csv', 
    index_col='no',
    usecols=['no', 'city', 'companyFullName', 'positionName', 'industryField', 'salary']
)
lagou_df.shape
#(3140,5)
# 数据清洗:找出“数据分析”岗位(positionName)的数据,并将薪资(salary)范围处理成中间值。
lagou_df = lagou_df[lagou_df.positionName.str.contains('数据分析')]
lagou_df.tail()
# 分组捕获
temp = lagou_df.salary.str.extract('(\d+)[kK]?-(\d+)[kK]?').applymap(int)
temp
# temp里有两列
lagou_df.loc[:, 'salary'] = temp.mean(axis=1)
# 数据分析:找出各大城市(city)数据分析岗位的需求量并绘制柱状图。
lagou_df.city.value_counts()

ser = lagou_df.groupby('city').companyFullName.count()
ser.plot(figsize=(10, 4), kind='bar', color=['r', 'g', 'b', 'y'], width=0.8)
# 定制网格线 ---> alpha(透明度)、linestyle(线条样式)、axis(轴)
plt.grid(True, alpha=0.25, linestyle=':', axis='y')
# 定制横轴的刻度
plt.xticks(rotation=0)
# 定制纵轴的刻度
plt.yticks(np.arange(0, 501, 50))
# 定制横轴的标签
plt.xlabel('')
# 定制图表的标题
plt.title('各大城市岗位数量')
for i in range(ser.size):
    # 在图表上添加文字
    plt.text(i, ser[i], ser[i], ha='center')
plt.show()
# 数据分析:找出不同领域(industryField)对数据分析岗位的需求量的占比并绘制饼图。
temp = lagou_df.industryField.str.split(pat='[丨,]', expand=True)
lagou_df['modifiedIndustryField'] = temp[0]
ser = lagou_df.groupby('modifiedIndustryField').companyFullName.count()
explodes = [0, 0.15, 0, 0, 0.05, 0, 0, 0, 0, 0]
ser.nlargest(10).plot(
    figsize=(6, 6), 
    kind='pie', 
    autopct='%.2f%%',
    pctdistance=0.75,
    shadow=True,
    explode=explodes,
    wedgeprops={
        'edgecolor': 'white',
        'width': 0.5
    }
)
plt.ylabel('')
plt.show()

# 数据分析:分析各城市的薪资水平并绘制折线图
ser = np.round(lagou_df.groupby('city').salary.mean(), 2)
ser.plot(figsize=(8, 4), kind='bar')
ser.plot(kind='line', color='red', marker='o', linestyle='--')
plt.show()

提取2019年的订单数据

# 提取2019年的订单数据
from datetime import datetime

start = datetime(2019, 1, 1)
end = datetime(2019, 12, 31, 23, 59, 59)
order_df.drop(index=order_df[order_df.orderTime < start].index, inplace=True)
order_df.drop(index=order_df[order_df.orderTime > end].index, inplace=True)
order_df.shape

处理支付时间早于下单时间的数据

# 处理支付时间早于下单时间的数据
order_df.drop(order_df[order_df.payTime < order_df.orderTime].index, inplace=True)
order_df.shape

折扣字段的处理

# 添加折扣字段,处理折扣大于1的字段(将支付金额修改为“订单金额*平均折扣”)
order_df['discount'] = np.round(order_df.payment / order_df.orderAmount, 4)
mean_discount = np.mean(order_df[order_df.discount <= 1].discount)
order_df['discount'] = order_df.discount.apply(lambda x: x if x <= 1 else mean_discount)
order_df['payment'] = order_df.orderAmount * order_df.discount

显示整体分析

print(f'GMV: {order_df.orderAmount.sum() / 10000:.4f}万元')
print(f'总销售额: {order_df.payment.sum() / 10000:.4f}万元')
real_total = order_df[order_df.chargeback == "否"].payment.sum()
print(f'实际销售额: {real_total / 10000:.4f}万元')
back_rate = order_df[order_df.chargeback == '是'].orderID.size / order_df.orderID.size
print(f'退货率: {back_rate * 100:.2f}%')
print(f'客单价:{real_total / order_df.userID.nunique():.2f}元')
print(order_df[order_df.chargeback == '是'].orderID.size)

np.mean(order_df[order_df.discount <= 1].discount)
order_df[‘discount’] = order_df.discount.apply(lambda x: x if x <= 1 else mean_discount)
order_df[‘payment’] = order_df.orderAmount * order_df.discount


显示整体分析

```python
print(f'GMV: {order_df.orderAmount.sum() / 10000:.4f}万元')
print(f'总销售额: {order_df.payment.sum() / 10000:.4f}万元')
real_total = order_df[order_df.chargeback == "否"].payment.sum()
print(f'实际销售额: {real_total / 10000:.4f}万元')
back_rate = order_df[order_df.chargeback == '是'].orderID.size / order_df.orderID.size
print(f'退货率: {back_rate * 100:.2f}%')
print(f'客单价:{real_total / order_df.userID.nunique():.2f}元')
print(order_df[order_df.chargeback == '是'].orderID.size)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值