统计计算和描述
常用的统计计算:
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,去掉了缺失值
- axis:
# 去掉所有包含缺失值的行——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)
网友评论