python数据分析之Pandas数据统计/分组/连接/清洗/重构

统计计算和描述

常用的统计计算:
sum、mean、max、min
axis=0 按列统计,axis=1 按行统计(axis=0时,表示最后的数据是一行,所以需要按列统计,axis=1时,表示最后的数据是一列,所以需要按行统计)


image.png

image.png
df_obj = pd.DataFrame(np.random.randn(5,4), columns = ['a', 'b', 'c', 'd'])
print(df_obj)

df_obj.sum()
df_obj.max()
df_obj.min(axis=1)
# 统计描述
df_obj.describe()

层级索引
1、MultiIndex对象
2、选取子集
外层选取 ser_obj['outer_label']
内层选取 ser_obj[:,'inner_label']
3、常用于分组操作、透视表的生成等
4、交换分层顺序 swaplevel()
5、排序分层 sortlevel()

import pandas as pd
import numpy as np

ser_obj = pd.Series(np.random.randn(12),
                    index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd'],
                           [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]])
print(ser_obj)
# MultiIndex索引对象
print(type(ser_obj.index))
print(ser_obj.index)

#选取子集
print(ser_obj['c'])   # 外层选取
print(ser_obj[:, 2])   # 内层选取

# 交换分层顺序
print(ser_obj.swaplevel())

#交换并排序分层
print(ser_obj.swaplevel().sortlevel())

分组与聚合 GroupBy对象

1、对数据集进行分组,然后对每组进行统计分析
2、SQL能够对数据进行过滤,分组聚合
3、pandas能利用groupby进行更加复杂的分组运算
4、分组运算过程(和Hadoop的mapreduce类似)
split -> apply ->combine
拆分:进行分组的依据
应用:每个分组运行的计算规则
合并:把每个分组的计算结果合并起来

import pandas as pd
import numpy as np

dict_obj = {'key1' : ['a', 'b', 'a', 'b', 
                      'a', 'b', 'a', 'a'],
            'key2' : ['one', 'one', 'two', 'three',
                      'two', 'two', 'one', 'three'],
            'data1': np.random.randn(8),
            'data2': np.random.randn(8)}
df_obj = pd.DataFrame(dict_obj)
print(df_obj)

#GroupBy对象,DataFrameGroupBy,SeriesGroupBy
# dataframe根据key1进行分组
print(type(df_obj.groupby('key1')))
# data1列根据key1进行分组
print(type(df_obj['data1'].groupby(df_obj['key1'])))

# 分组运算
grouped1 = df_obj.groupby('key1')
print(grouped1.mean())

grouped2 = df_obj['data1'].groupby(df_obj['key1'])
print(grouped2.mean())

# size(),返回每个分组的元素个数
print(grouped1.size())
print(grouped2.size())

# 按列名分组
df_obj.groupby('key1')

# 按自定义key分组,列表
self_def_key = [1, 1, 2, 2, 2, 1, 1, 1]
df_obj.groupby(self_def_key).size()

# 按自定义key分组,多层列表
df_obj.groupby([df_obj['key1'], df_obj['key2']]).size()

# 按多个列多层分组
grouped2 = df_obj.groupby(['key1', 'key2'])
print(grouped2.size())

#GroupBy对象分组迭代
# GroupBy对象支持迭代操作,每次迭代返回一个元组( group_name, group_data)
for group_name, group_data in grouped2:
    print(group_name)
    print(group_data)

# GroupBy对象转换list
list(grouped1)

# GroupBy对象转换dict
dict(list(grouped1))

# 按列分组
print(df_obj.dtypes)

# 按数据类型分组
df_obj.groupby(df_obj.dtypes, axis=1).size()
df_obj.groupby(df_obj.dtypes, axis=1).sum()

聚合aggregation

dict_obj = {'key1' : ['a', 'b', 'a', 'b', 
                      'a', 'b', 'a', 'a'],
            'key2' : ['one', 'one', 'two', 'three',
                      'two', 'two', 'one', 'three'],
            'data1': np.random.randint(1,10, 8),
            'data2': np.random.randint(1,10, 8)}
df_obj5 = pd.DataFrame(dict_obj)
print(df_obj5)

# 内置的聚合函数
print(df_obj5.groupby('key1').sum())
print(df_obj5.groupby('key1').max())
print(df_obj5.groupby('key1').min())
print(df_obj5.groupby('key1').mean())
print(df_obj5.groupby('key1').size())
print(df_obj5.groupby('key1').count())
print(df_obj5.groupby('key1').describe())

# 自定义聚合函数,传入agg方法中
def peak_range(df):
    """
        返回数值范围
    """
    #print type(df) #参数为索引所对应的记录
    return df.max() - df.min()

print(df_obj5.groupby('key1').agg(peak_range))
print(df_obj5.groupby('key1').agg(lambda df : df.max() - df.min()))

# 应用多个聚合函数

# 同时应用多个聚合函数
print(df_obj5.groupby('key1').agg(['mean', 'std', 'count', peak_range])) # 默认列名为函数名
print(df_obj5.groupby('key1').agg(['mean', 'std', 'count', ('range', peak_range)])) # 通过元组提供新的列名

# 每列作用不同的聚合函数,使用dict
dict_mapping = {'data1':'mean',
                'data2':'sum'}
print(df_obj5.groupby('key1').agg(dict_mapping))
dict_mapping = {'data1':['mean','max'],
                'data2':'sum'}
print(df_obj5.groupby('key1').agg(dict_mapping))

数据分组运算

聚合运算改变了原始数据的shape,那么如何保持原始数据的shape呢
1、使用merge的外连接,比较复杂
2、使用 transform

import pandas as pd
import numpy as np
# 分组运算后保持shape
dict_obj = {'key1' : ['a', 'b', 'a', 'b', 
                      'a', 'b', 'a', 'a'],
            'key2' : ['one', 'one', 'two', 'three',
                      'two', 'two', 'one', 'three'],
            'data1': np.random.randint(1, 10, 8),
            'data2': np.random.randint(1, 10, 8)}
df_obj = pd.DataFrame(dict_obj)

# 按key1分组后,计算data1,data2的统计信息并附加到原始表格中
k1_sum = df_obj.groupby('key1').sum()

# 方法1,使用merge
pd.merge(df_obj, k1_sum, left_on='key1', right_index=True)
# 方法2,使用transform
k1_sum_tf = df_obj.groupby('key1').transform(np.sum).add_prefix('sum_')
df_obj[k1_sum_tf.columns] = k1_sum_tf
df_obj
# 自定义函数传入transform
def diff_mean(s):
    """
        返回数据与均值的差值
    """
    return s - s.mean()

df_obj.groupby('key1').transform(diff_mean)

# apply 
def top_n(df, n=3, column='APM'):
    """
        返回每个分组按 column 的 top n 数据
    """
    return df.sort_values(by=column, ascending=False)[:n]

df_data.groupby('LeagueIndex').apply(top_n)

数据清洗

1、数据清洗是数据分析关键的一步,直接影响之后的处理工作
2、数据需要修改么,有什么需要修改的么,数据应该怎么调整才能适用于借来的分析和挖掘?
3、是一个迭代的过程,实际项目中可能需要不知一次地执行这些清洗操作
4、处理缺失数据 pd.fillna(),pd.dropna()

过滤
  • query过滤
# age是列名
 df.query('age>20 & age<40')
  • loc 索引过滤
df.loc[(df.age>20) & (df.color.notnull())]
# 注意在逻辑操作符两边的过滤条件必须使用小括号括起来,否则条件过滤不起作用
处理缺失数据
  • 1.对缺失值进行填充——fillna
    使用DataFrame.fillna(value=None, method=None, axis=None,)
    value: scalar, dict, Series, or DataFrame,dict 可以指定每一行或列用什么值填充
    method: {‘backfill’, ‘bfill’, ‘pad’, ‘ffill’, None}, default None
    在列上操作
    • ffill / pad: 使用前一个值来填充缺失值
    • backfill / bfill :使用后一个值来填充缺失值
# 用值为x的数来对缺失值进行填充
df.fillna(value=x)

# 每一列使用不同的缺失值
values = {'A': 0, 'B': 1, 'C': 2, 'D': 3}
df.fillna(value=values)

# 使用后边或前边的值填充缺失值
df.fillna(method='ffill')
df.fillna(method='bfill')

  • 2.去掉包含缺失值的行
    使用DataFrame.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)
    参数说明:
    • axis:
      axis=0: 删除包含缺失值的行
      axis=1: 删除包含缺失值的列
    • how: 与axis配合使用
      how=‘any’ :只要有缺失值出现,就删除该行货列
      how=‘all’: 所有的值都缺失,才删除行或列
    • thresh: axis中至少有thresh个非缺失值,否则删除
      比如 axis=0,thresh=10:标识如果该行中非缺失值的数量小于10,将删除改行
    • subset: list
      在哪些列中查看是否有缺失值
    • inplace: 是否在原数据上操作。如果为真,返回None否则返回新的copy,去掉了缺失值
# 去掉所有包含缺失值的行——dropna
df.dropna(how='any')
# 在指定'name', 'born'列中如有缺失值,则删除对应的行
df.dropna(subset=['name', 'born'])
# 如果行中非缺失值的数目小于2个,则删除该行
df.dropna(thresh=2)
  • 3.删除行 或者 列——drop
    可以使用dropna 或者drop函数
    DataFrame.drop(labels=None, axis=0, index=None, columns=None, level=None, inplace=False, errors='raise')
    参数说明:
    • labels: 要删除行或列的列表
    • axis: 0 行 ;1 列
    • columns:要删除的列
# 删除B,C两列
df.drop(columns=['B', 'C'])
# 删除行(索引)
df.drop([0, 1])

数据连接 merge

1、根据单个或多个键将不同的DataFrame的行连接起来
2、类比sql join操作
3、默认将重叠列的列名作为“外键”进行连接
on 显式的指定 “外键”
left_on 左侧数据的外键
right_on 右侧数据的外键
4、默认是 “内连接”(inner),即结果中的键是交集

import pandas as pd
import numpy as np

df_obj1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],
                        'data1' : np.random.randint(0,10,7)})
df_obj2 = pd.DataFrame({'key': ['a', 'b', 'd'],
                        'data2' : np.random.randint(0,10,3)})

# 默认将重叠列的列名作为“外键”进行连接,默认是 “内连接”(inner)
#这里相当于 mysql 的  inner join
pd.merge(df_obj1, df_obj2)

# on显示指定“外键”
pd.merge(df_obj1, df_obj2, on='key')
# left_on,right_on分别指定左侧数据和右侧数据的“外键”
# 更改列名
df_obj1 = df_obj1.rename(columns={'key':'key1'})
df_obj2 = df_obj2.rename(columns={'key':'key2'})
pd.merge(df_obj1, df_obj2, left_on='key1', right_on='key2')

#how指定连接方式
# “外连接”,outer,j结果中的键是并集
pd.merge(df_obj1, df_obj2, left_on='key1', right_on='key2', how='outer')
# 左连接 left
pd.merge(df_obj1, df_obj2, left_on='key1', right_on='key2', how='left')
# 右连接 right
pd.merge(df_obj1, df_obj2, left_on='key1', right_on='key2', how='right')

# 处理重复列名
df_obj1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],
                        'data' : np.random.randint(0,10,7)})
df_obj2 = pd.DataFrame({'key': ['a', 'b', 'd'],
                        'data' : np.random.randint(0,10,3)})

print(df_obj1)
print(df_obj2)
pd.merge(df_obj1, df_obj2, on='key', suffixes=('_left', '_right'))

# 按索引连接
df_obj1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],
                        'data1' : np.random.randint(0,10,7)})
df_obj2 = pd.DataFrame({'data2' : np.random.randint(0,10,3)}, index=['a', 'b', 'd'])
print(df_obj1)
print(df_obj2)
pd.merge(df_obj1, df_obj2, left_on='key', right_index=True)

数据合并 concat

沿轴方向将多个对象合并到一起

import numpy as np
import pandas as pd
#NumPy的concat,np.concatenate
arr1 = np.random.randint(0, 10, (3, 4))
arr2 = np.random.randint(0, 10, (3, 4))

np.concatenate([arr1, arr2])
np.concatenate([arr1, arr2], axis=1)

#Series上的concat
# index 没有重复的情况
ser_obj1 = pd.Series(np.random.randint(0, 10, 5), index=range(0,5))
ser_obj2 = pd.Series(np.random.randint(0, 10, 4), index=range(5,9))
ser_obj3 = pd.Series(np.random.randint(0, 10, 3), index=range(9,12))

pd.concat([ser_obj1, ser_obj2, ser_obj3]) #默认axis = 0
pd.concat([ser_obj1, ser_obj2, ser_obj3], axis=1)

# index 有重复的情况
ser_obj1 = pd.Series(np.random.randint(0, 10, 5), index=range(5))
ser_obj2 = pd.Series(np.random.randint(0, 10, 4), index=range(4))
ser_obj3 = pd.Series(np.random.randint(0, 10, 3), index=range(3))
pd.concat([ser_obj1, ser_obj2, ser_obj3])

#join指定合并方式,默认为ourter
pd.concat([ser_obj1, ser_obj2, ser_obj3], axis=1, join='inner')

#DataFrame上的concat
df_obj1 = pd.DataFrame(np.random.randint(0, 10, (3, 2)), index=['a', 'b', 'c'],
                       columns=['A', 'B'])
df_obj2 = pd.DataFrame(np.random.randint(0, 10, (2, 2)), index=['a', 'b'],
                       columns=['C', 'D'])

pd.concat([df_obj1, df_obj2])
pd.concat([df_obj1, df_obj2], axis=1)

数据重构stack

1、将列索引旋转为行索引,完成层级索引
2、DataFrame -> Series

import numpy as np
import pandas as pd

df_obj = pd.DataFrame(np.random.randint(0,10, (5,2)), columns=['data1', 'data2'])
# stack将列索引旋转为行索引,完成层级索引,DataFrame -> Series
stacked = df_obj.stack()
print(stacked)

# 默认操作内层索引
# unstack将层级索引展开,Series -> DataFrame ,默认操作内层索引,即level =-1
#stacked.unstack()
# 通过level指定操作索引的级别
stacked.unstack(level=0)

数据转换

import numpy as np
import pandas as pd
df_obj = pd.DataFrame({'data1' : ['a'] * 4 + ['b'] * 4,
                       'data2' : np.random.randint(0, 4, 8)})

#重复数据
df_obj.duplicated()
#删除重复数据
df_obj.drop_duplicates()
#删除指定列重复数据
df_obj.drop_duplicates('data2')

#map函数
ser_obj = pd.Series(np.random.randint(0,10,10))

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

推荐阅读更多精彩内容