Python数据分析案例总结 2020.3.12

近期做了四个Python数据分析的案例实践,把流程、语句和想法归纳总结,做一个小小的里程碑

1.流程

明确分析目的->由数据源构建指标体系->数据清洗->数据处理及分析->结论

2.明确分析目的

-->分析问题产生的原因/分析业务现状/通过分析对业务进行指导……
目的——是具体的、充满定语的、具有返回值的

3.由数据源构建指标体系

区分维度和指标:
维度:对应数据的每一列,多个列组合也可以认为是一个维度
指标:各种统计值
在不同维度上得到各种指标
根据不同数据源和分析目的搭建指标体系
eg:一款付费软件的日活/人均付费/付费渠道/付费功能/使用频次/使用时长……

4.数据清洗

4.1导入库

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

4.2加载文件

df = pd.read_csv('./file.csv')

4.3简单查看数据有哪些列&类型

df.info() # 可看到缺失行在某一列上的条目数少于总数,但当列数目较多时,不容易发现
df.head()

4.4查看数据的整体信息

df.describe()  # 整数型或浮点型数据
df.count() # 查看各列非空数据量

4.5开始数据清理

->对需要分析的维度进行清理
->对于数值型数据,可以通过describe方法输出信息,关注最大值、最小值、平均值、行数等是否符合常理或是否满足本次数据分析目的对数据的要求

4.5.1判断数据是否有null值、0值等

若null值所在行数较少,删除后不会对总体数据产生较大影响

df[df.salary.isnull()] 输出salary列null值所在行的全部信息
df.drop(df[df.salary.isnull()].index, inplace = True)
df[df.salary.isnull()] # 查看是否删除成功

若不想删除数据,则可用聚合函数或前值/后值等替换处理,如使用平均数替换

df['salary'].replace(0,df['salary'].mean(), inplace = True)
# 注:若遇到较多0值,且要采用平均数填充,可先将0值替换为np.nan,再使用列名.fillna()填充该列数据平均数,这样在计算平均数时nan所在行不会对整体平均数产生影响(不计入在内)
df.salary.replace(0,np.nan, inplace = True)
df.salary.fillna(df['salary'].mean(), inplace=Ture)
df['communityAverage'].fillna(df['communityAverage'].mean(), inplace=True) # 对null值,也可使用fillna

df.info() 查看是否有Nan值
Nan非null值,无法用 .isnull()判断
但通过df.info()判断存在缺失值,但又不是null时,可查看其是否为Nan值

df['Type'].value_counts(dropna = False) #统计包括Nan在内的数据
data.dropna()  # 默认axis=0,how='any',删除带有空值的行,只要有一个空值,就删除整行
df.dropna(how='all')            # 整行都是空值时,才会被删除
df.dropna(how='all',axis=1))    # 整列都是空值时,才会被删除
df.dropna(subset=[1,2])         # 删除指定1和2列中包含缺失值的行

4.5.2 查看是否具有重复值,展示重复的条目

如果有重复值,⼀般最后处理,因为其他的列可能会影响到删除那⼀条重复的记录
先处理其他的列

df[df.duplicated()]  #注意这样使用是展示各字段完全相同的条目
df.drop_duplicates('App', inplace = True)# 删除'App'列中数据重复的行

也可根据指定部分列(待分析列)是否具有重复值

df[df[:,['employee_ID','deptno_ID','salary']].dupliacted()]
df[df.employee_ID.dupliacted()] # 单独查看employee_ID是否具有重复值的条目

或使用行数是否相等来判断

len(df.empolyee_ID.unique()) 与 len(df) # 是否相等,相等->该列无重复
df['employee_ID'].value_counts() # 默认剔除nan值 # 是否有大于1的
df['employee_ID'].value_counts(dropna = False) # 计算包含nan值的条目
pd.unique(df['employee_ID']).size # 是否与整个数据行数相同

注意:当我们对⼀列取size属性的时候,返回的是⾏数,如果对于dataframe使⽤size,返回的是行乘以列的结果,也就是总的元素数

4.5.3 删除非所需数据

df.drop(df[df['hiretime'].dt.year<2015].index, inplace = True)
df.drop(df[df['hiretime'].dt.year>2019].index, inplace = True)
df['hiretime'].dt.year.value_counts()

4.5.4 使用分类查看是否有不合逻辑的类型

df['nationality'].value_counts()

比如该列都是用国家英文全称来填充的,但某个结果中若出现数字-->不合逻辑-->是因为没有把数字标号转换为国家还是因为其他原因?

4.5.5 判断字符串类型数据是否只由数字组成

df['deptno_info'].str.isnumeric() --> True or False
df['deptno_info'].str.isnumeric().sum() -->True 的条目数

数据格式转换

    df['deptno_info'].astype('i8') #将本列转换为数值格式

说明:
isnumeric() 方法检测字符串是否只由数字组成。这种方法是只针对unicode对象。
注:定义一个字符串为Unicode,只需要在字符串前添加 'u' 前缀即可,如 str1 = u'Itachi';
对于 Unicode 数字、全角数字(双字节)、罗马数字和汉字数字会返回 True ,其他会返回 False。byte数字(单字节)无此方法。

print u'123'.isnumeric() # True
print u'Ⅷ'.isnumeric() # True
print u'abc123'.isnumeric() # False
print u'1.23'.isnumeric() # False

4.5.6 单位转化 str.replace()

eg:数据单位的简化处理
tips:转化为数据较小单位时可以实现-->转化后数据成为整数int类型,而非float

df['size'] = df['size'].replace('M','e+6') #M-->10^6 
df['size'] = df['size'].replace('k','e+3') #k-->10^3
df['size'] = df['size'].replace(',','') # 替换千位符
df['Size'].astype('f8')

使用is_convertable(v)函数定义一个方法,判断字符串判断是否可以转换

def is_convertable(v): 
    try:
        float(v)
        return True
    except ValueError:
        return False

查看不能转换的字符串分布

temp = df['size'].apply(is_convertable) -->能转换 True
df['size'][-temp].value_counts() --> -temp 取False的
# 转换剩下的字符串
df['size'] = df['size'].str.replace('Varies with device','0')
# 再看下是不是还有没转换的字符串
temp = df['size'].apply(is_convertable)
df['size'][-temp].value_counts()
# 转换类型
# e+5这种格式使⽤astype直接转为int有问题,如果想转成int,可以先转成f8,再转i8
#df['size'] = df['size'].astype('f8').astype('i8')
df['size'] = df['size'].astype('i8')
# 将size为0的填充为平均数
df['size'].replace(0,df['size'].mean(), inplace = True)
df.describe()

5.数据分析

5.1样本总数

df.count()

5.2数值类型列的常见统计指标

df.describe()

5.3采用不同维度和指标进行分析

① 分组 groupby
分组统计不同国家人员并保留两列

nationality_data = df.groupby('nationality',as_index = False).count()[['nationality', 'ID']]
nationality_data.rename(columns={'ID':'employee_count'},inplace = True) #重命名ID列-->上述操作后ID列实际为总数

不同部门中雇员平均工资

deptno_data = df.groupby('deptno',as_index = False).mean()[['deptno','salary']

对不同分组下另一维度进行排序
eg:对App分类分组后计算其他维度平均值,并按照平均安装量对各组降序排列

df.groupby('category').mean().sort_values('installs', ascending = False)

多列分组

# type --> free or charges
# category --> family or media or chat ..........
df.groupby(['type','category'].mean().sort_values('reviews', ascending = True/False, inplace = True/False)

② 分类计数

groupby().count()
df.groupby('nationality').count()
value_counts() 

eg:统计每年入职人数
年份跨度较大时,有些年份可能数据较少;年初或年中时,当年数据可能较少
看下每年数据的数量,确定是否要删除数据少的年份
将字符串转化为日期格式,方便使用内置函数

df['hiretime'] = pd.to_datetime(df['hiretime'])
df['hiretime'].dt.year.value_counts()

分类计算比例
eg:对类型和分类分组后,对其评论安装比进行排序

g = df.groupby(['type','category']).mean()
(g['reviews'] / g['installs']).sort_values(ascending = False)

③ 按照数值排序 sort_values()

nationality_sorted_data = nationality_data.sort_values('employee_count', ascending=False)
nationality_sorted_data[nationality_sorted_data.employee_count>100] # 显示employee_count数量大于100的数据列表
df.sort_index(inplace = True) # 按照索引排序 sort_index() 

④ 分桶 pd.cut-groupby
雇员年龄分布
生成桶,5岁一个分桶 最小18岁,最大60岁

bins = np.arange(18,63,5)
bins_data = pd.cut(df['age'],bins)
bin_counts = df['age'].groupby(bins_data).count()
# 为图表展示好看使用列表生成式处理index
bin_counts.index = [str(x.left) + '-' + str(x.right) for x in bin_counts.index]

⑤ 单独取出某列
eg:取出2017年,国籍为China的所有数据

df_2017 = df[df['hiretime'].dt.year == 2017]
df_2017_China = df_2017[df_2017['nationality'] == 'China']
df_2017_China.describe()

⑥ 占比 len()/len()
统计salary在50~100之间的数据在所有数据中的占比

len(df[df['salary'] > 50]) & len(df[df['salary'] < 100])/len(df)

⑦ 相关性(0.5以上可以认为相关,0.3以上可以认为是弱相关)

df.corr() # 列出二维相关性表

⑧ .head() .tail()

# 取某维度的前十名和后十名
print(product_orderby_count.head(10))
print(product_orderby_count.tail(10))

⑨ .intersection() 交集
看下销售额和销量最后100个的交集,如果销售额和销量都不行,这些商品需要看看是不是要优化或者下架

problem_productids = productid_turnover.tail(100).intersection(product_orderby_count.tail(100).index)

5.4 matplotlib查看数据效果

bin_counts.plot()
plt.show()

注意点:
1.drop、rename等方法具有inplace参数,具体见帮助文档,学习初期往往忽略此参数,导致数据未在原表上修改或未设置接收变量。运行后无输出则说明inplace为TRUE(jupyter notebook的使用优点),若有输出则应赋予接收变量或为inplace赋值;而replace没有inplace参数,需要设置接收值
2.对多列进行操作时,留心是否需要多加一层括号,如 df.groupby(['district', 'elevator'])
3.注意到df_dis_want[(df['year'] == '2017')]判别条件这里,数据类型不同判别条件中需要考虑是否加引号'',或者可认为是数据清洗环节的疏漏

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341

推荐阅读更多精彩内容