之前由于为了使用,简单的学习下Pandas,而后发现它是个强大的家伙~,因为python版本进行了更新,随之有些api有所改动,所以重新整理官网入门级demo教程来加深印象~
Pandas易于使用的数据结构和数据分析工具。中文称呼为:熊猫!
这是关于pandas的简短介绍,主要面向新用户。可以参阅Cookbook了解更复杂的使用方法。习惯上,我们做以下导入
import pandas as pd
import numpy as np
import matplotlib.pyplot as pl
请参阅数据结构介绍部分
s = pd.Series([1,3,5,np.nan,6,8])
s
dates = pd.date_range('20130101', periods=6)
dates
df = pd.DataFrame(np.random.randn(6,4), index=dates, columns=list('ABCD'))
df
DataFrame通过传递一个字典,可以转换为一序列对象。
df2 = pd.DataFrame({ 'A' : 1.,
'B' : pd.Timestamp('20130102'),
'C' : pd.Series(1,index=list(range(4)),dtype='float32'),
'D' : np.array([3] * 4,dtype='int32'),
'E' : pd.Categorical(["test","train","test","train"]),
'F' : 'foo' })
df2
明确所有类型
df2.dtype
# 查看框架的顶部和底部的行
df.head()#全部内容
df.tail(3)#底部三行
#显示索引,列和底层numpy数据
df.index #显示索引kye
df.columns# 显示列值*(A,B,C,D)
df.values #只显示值
# 描述显示您的数据的快速统计摘要
df.describe()
#转置您的数据
df.T #x-y颠倒
# 按轴排序
df.sort_index(axis=1, ascending=False)
# 按值排序
df.sort_values(by='B')
注释: 标准Python / Numpy表达式可以完成这些互动工作, 但在生产代码中, 我们推荐使用优化的pandas数据访问方法, .at, .iat, .loc, .iloc 和 .ix.
# 读取
# 选择单列, 这会产生一个序列, 等价df.A
df['A']
# 选择通过[],切行片
df[0:3] #取前面三行
df['20130102':'20130104'] #取包含2013-01-02 到2013-01-04和之间的数据
# 使用标签获取横截面
df.loc[dates[0]] # dates 索引为零的行数据
# 使用标签选择多轴
df.loc[:,['A','B']] #取a到b两列纵行
# 显示标签切片, 包含两个端点
df.loc['20130102':'20130104',['A','B']] #显示20130102到20130104行数,然后a-b的纵行。
# 降低返回对象维度
df.loc['20130102',['A','B']]
# 获取标量值
df.loc[dates[0],'A'] #获取dates索引为零的的行行以及A列交叉的值。
# 按位置选择更多内容
df.iloc[3] #取出y轴索引为3的值,x轴数据,
df.iloc[3:5,0:2] #y轴,x轴范围过滤,索引3到索引5(不包括索引5),x轴(0-2)不包括2 通过整数片,类似于numpy / python
df.iloc[[1,2,4],[0,2]] #整数位置的位置列表,类似于numpy / python风格
#用于明确地切割行
df.iloc[1:3,:] # 输出y轴索引1到索引2,不包括索引3,然后x轴全部的值。
df.iloc[:,1:3] # 输出x轴索引1-2的值,y轴全部,用于明确地切分列
# 为了明确地获取一个值
df.iloc[1,1]
# 为了快速访问标量(等同于之前的方法)
df.iat[1,1]
# 使用单个列的值来选择数据。
df[df.A > 0]
# 从满足布尔条件的DataFrame中选择值
df[ df > 0 ]
# 使用isin()过滤方法
df2 = df.copy()
df2['E'] = ['one', 'one','two','three','four','three']
df2
df2[df2['E'].isin(['two','four'])]
#设置新列自动按索引排列数据
s1 = pd.Series([1,2,3,4,5,6], index=pd.date_range('20130102', periods=6))
s1
df.at[dates[0], 'A'] = 0 # 通过标签设置值
df.iat[0, 1] = 0 #按位置设置值
df.loc[:,'D'] = np.array([5] * len(df)) #通过分配一个numpy数组进行设置
df
# 条件设置操作。
df2 = df.copy()
df2[df2 > 0] = -df2
df2
# 熊猫主要使用这个值np.nan来表示缺失的数据
# Reindexing允许您更改/添加/删除指定轴上的索引。这将返回数据的副本。
df1 = df.reindex(index=dates[0:4], columns=list(df.columns) + ['E']) #添加E列,因为没赋值都是NaN!
df1
df1.loc[dates[0]:dates[1],'E'] = 1 # 在E列上y轴索引0,1设置值为1.
df1
# 删除任何缺少数据的行
df1.dropna(how='any')
# 填写缺少的数据
df1.fillna(value=6) #把NaN,无效的值,用6代替。
# 获取值是否nan的布尔标记
pd.isnull(df1)
# 运算一般操作不包括丢失的数据。
df.mean() #执行描述性统计
df.mean(1)#相同的操作在另一个轴上
# 用于运算的对象有不同的维度并需要对齐.除此之外,pandas会自动沿着指定维度计算.
s = pd.Series([1,3,5,np.nan,6,8],index=dates).shift(2) #索引保持不动,值被下移动两位
s
df
df.sub(s,axis='index')
# 在数据上使用函数
df.apply(np.cumsum)
df.apply(lambda x: x.max() - x.min())
# 直方图
s = pd.Series(np.random.randint(0, 7, size=10))
s
s.value_counts()
# 字符串方法
# 序列可以使用一些字符串处理方法很轻易操作数据组中的每个元素,比如以下代码片断。 注意字符匹配方法默认情况下通常使用正则表达式(并且大多数时候都如此). 更多信息请参阅字符串向量方法.
s = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan, 'CABA', 'dog', 'cat'])
s.str.lower()
# pandas提供各种工具以简便合并序列,数据桢,和组合对象, 在连接/合并类型操作中使用多种类型索引和相关数学函数.
df = pd.DataFrame(np.random.randn(10, 4))
df
pieces = [df[:3], df[3:7], df[7:]]
pd.concat(pieces)
# SQL样式合并、
left = pd.DataFrame({'key': ['foo', 'foo'], 'lval': [1, 2]})
right = pd.DataFrame({'key': ['foo', 'foo'], 'rval': [4, 5]})
left
right
pd.merge(left, right, on='key')
# 添加行到数据
df = pd.DataFrame(np.random.randn(8, 4), columns=['A','B','C','D'])
df
s = df.iloc[3]
df.append(s, ignore_index=True)
# 分组将数据按某些标准分割为不同的,在每个独立组上应用函数组合结果为一个数据结构
df = pd.DataFrame({'A' : ['foo', 'bar', 'foo', 'bar', 'foo', 'bar', 'foo', 'foo'],
'B' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'],
'C': np.random.randn(8),
'D' : np.random.randn(8)})
df
# 分组然后应用函数统计总和存放到结果组
df.groupby('A').sum()
# 按多列分组为层次索引,然后应用函数
df.groupby(['A','B']).sum()
# 堆叠
tuples = list(zip(*[['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'],
['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']]))
index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
df = pd.DataFrame(np.random.randn(8, 2), index=index, columns=['A', 'B'])
df2 = df[:4]
df2
# 堆叠 函数 “压缩” 数据桢的列一个级别.
stacked = df2.stack()
stacked
# 被“堆叠”数据桢或序列(有多个索引作为索引), 其堆叠的反向操作是未堆栈, 上面的数据默认反堆叠到上一级别:
stacked.unstack()
stacked.unstack(1)
stacked.unstack(0)
# 数据透视表
df = pd.DataFrame({'A' : ['one', 'one', 'two', 'three'] * 3,
'B' : ['A', 'B', 'C'] * 4,
'C' : ['foo', 'foo', 'foo', 'bar', 'bar', 'bar'] * 2,
'D' : np.random.randn(12),
'E' : np.random.randn(12)})
df
#x轴列字段为C,y轴索引为,AB,值为D字段
pd.pivot_table(df, values='D', index=['A', 'B'], columns=['C'])
# 时间序列,pandas有易用,强大且高效的函数用于高频数据重采样转换操作
rng = pd.date_range('1/1/2012', periods=100, freq='S')
ts = pd.Series(np.random.randint(0, 500, len(rng)), index=rng)
ts.resample('5Min', how='sum')
# 时区表示
rng = pd.date_range('3/6/2012 00:00', periods=5, freq='D')
ts = pd.Series(np.random.randn(len(rng)), rng)
ts
ts_utc = ts.tz_localize('UTC')
ts_utc
# 转换到其它时区
ts_utc.tz_convert('US/Eastern')
# 转换不同的时间跨度
rng = pd.date_range('1/1/2012', periods=5, freq='M')
ts = pd.Series(np.random.randn(len(rng)), index=rng)
ts
ps = ts.to_period()
ps
ps.to_timestamp()
# 转换时段并且使用一些运算函数, 下例中, 我们转换年报11月到季度结束每日上午9点数据
prng = pd.period_range('1990Q1', '2000Q4', freq='Q-NOV')
ts = pd.Series(np.random.randn(len(prng)), prng)
ts.index = (prng.asfreq('M', 'e') + 1).asfreq('H', 's') + 9
ts.head()
# 分类
# 自版本0.15起, pandas可以在数据桢中包含分类
df = pd.DataFrame({"id":[1,2,3,4,5,6], "raw_grade":['a', 'b', 'b', 'a', 'a', 'e']})
# 转换原始类别为分类数据类型.
df["grade"] = df["raw_grade"].astype("category")
df["grade"]
# 重命令分类为更有意义的名称 (分配到Series.cat.categories对应位置!)
df["grade"].cat.categories = ["very good", "good", "very bad"]
# 重排顺分类,同时添加缺少的分类(序列 .cat方法下返回新默认序列)
df["grade"] = df["grade"].cat.set_categories(["very bad", "bad", "medium", "good", "very good"])
df["grade"]
# 类别列分组,并且也显示空类别
df.groupby("grade").size()
# 绘图
ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000))
ts = ts.cumsum()
ts.plot()
# 在数据桢中,可以很方便的绘制带标签列:
df = pd.DataFrame(np.random.randn(1000, 4), index=ts.index,columns=['A', 'B', 'C', 'D'])
df = df.cumsum()
plt.figure(); df.plot(); plt.legend(loc='best')
# 写入csv文件
df.to_csv('foo.csv')
# 读取csv文件
pd.read_csv('foo.csv')
# 写入HDF5存储
df.to_hdf('foo.h5','df')
# 读取HDF5存储
pd.read_hdf('foo.h5','df')
# 写入excel文件
df.to_excel('foo.xlsx', sheet_name='Sheet1')
# 读取excel文件
pd.read_excel('foo.xlsx', 'Sheet1', index_col=None, na_values=['NA'])
pandas基础
流处理
流处理,听起来很高大上啊,其实就是分块读取。有这么一些情况,有一个很大的几个G的文件,没办法一次处理,那么就分批次处理,一次处理1百万行,接着处理下1百万行,慢慢地总是能处理完的。
# 使用类似迭代器的方式
data=pd.read_csv(file, chunksize=1000000)
for sub_df in data:
print('do something in sub_df here')
索引
Series和DataFrame都是有索引的,索引的好处是快速定位,在涉及到两个Series或DataFrame时可以根据索引自动对齐,比如日期自动对齐,这样可以省去很多事。
缺失值
pd.isnull(obj)
obj.isnull()
将字典转成数据框,并赋予列名,索引
DataFrame(data, columns=['col1','col2','col3'...],
index = ['i1','i2','i3'...])
查看列名
DataFrame.columns
查看索引
DataFrame.index
重建索引
obj.reindex(['a','b','c','d','e'...], fill_value=0]
#按给出的索引顺序重新排序,而不是替换索引。如果索引没有值,就用0填充
#就地修改索引
data.index=data.index.map(str.upper)
列顺序重排(也是重建索引)
DataFrame.reindex[columns=['col1','col2','col3'...])`
#也可以同时重建index和columns
DataFrame.reindex[index=['a','b','c'...],columns=['col1','col2','col3'...])
重建索引的快捷键
DataFrame.ix[['a','b','c'...],['col1','col2','col3'...]]
重命名轴索引
data.rename(index=str.title,columns=str.upper)
#修改某个索引和列名,可以通过传入字典
data.rename(index={'old_index':'new_index'},
columns={'old_col':'new_col'})
查看某一列
DataFrame['state'] 或 DataFrame.state
查看某一行
需要用到索引
DataFrame.ix['index_name']
添加或删除一列
DataFrame['new_col_name'] = 'char_or_number'#删除行
DataFrame.drop(['index1','index2'...])
#删除列
DataFrame.drop(['col1','col2'...],axis=1)
#或del DataFrame['col1']
DataFrame选择子集
类型
|
说明
|
obj[val]
|
选择一列或多列
|
obj.ix[val]
|
选择一行或多行
|
obj.ix[:,val]
|
选择一列或多列
|
obj.ix[val1,val2]
|
同时选择行和列
|
reindx
|
对行和列重新索引
|
icol,irow
|
根据整数位置选取单列或单行
|
get_value,set_value
|
根据行标签和列标签选择单个值
|
针对series
obj[['a','b','c'...]]
obj['b':'e']=5
针对dataframe
#选择多列
dataframe[['col1','col2'...]]
#选择多行
dataframe[m:n]
#条件筛选
dataframe[dataframe['col3'>5]]
#选择子集
dataframe.ix[0:3,0:5]
dataframe和series的运算
会根据 index 和 columns 自动对齐然后进行运算,很方便啊
方法
|
说明
|
add
|
加法
|
sub
|
减法
|
div
|
除法
|
mul
|
乘法
|
#没有数据的地方用0填充空值
df1.add(df2,fill_value=0)
# dataframe 与 series 的运算
dataframe - series
规则是:
-------- -------- |
| | | | |
| | -------- |
| | |
| | v
--------
#指定轴方向
dataframe.sub(series,axis=0)
规则是:
-------- ---
| | | | ----->
| | | |
| | | |
| | | |
-------- ---
apply函数
f=lambda x:x.max()-x.min()
#默认对每一列应用
dataframe.apply(f)
#如果需要对每一行分组应用
dataframe.apply(f,axis=1)
排序和排名
#默认根据index排序,axis = 1 则根据columns排序
dataframe.sort_index(axis=0, ascending=False)
# 根据值排序
dataframe.sort_index(by=['col1','col2'...])
#排名,给出的是rank值
series.rank(ascending=False)
#如果出现重复值,则取平均秩次
#在行或列上面的排名
dataframe.rank(axis=0)
描述性统计
方法
|
说明
|
count
|
计数
|
describe
|
给出各列的常用统计量
|
min,max
|
最大最小值
|
argmin,argmax
|
最大最小值的索引位置(整数)
|
idxmin,idxmax
|
最大最小值的索引值
|
quantile
|
计算样本分位数
|
sum,mean
|
对列求和,均值
|
mediam
|
中位数
|
mad
|
根据平均值计算平均绝对离差
|
var,std
|
方差,标准差
|
skew
|
偏度(三阶矩)
|
Kurt
|
峰度(四阶矩)
|
cumsum
|
累积和
|
Cummins,cummax
|
累计组大致和累计最小值
|
cumprod
|
累计积
|
diff
|
一阶差分
|
pct_change
|
计算百分数变化
|
唯一值,值计数,成员资格
obj.unique()
obj.value_count()
obj.isin(['b','c'])
处理缺失值
# 过滤缺失值
# 只要有缺失值就丢弃这一行
dataframe.dropna()
#要求全部为缺失才丢弃这一行
dataframe.dropna(how='all')
# 根据列来判断
dataframe.dropna(how='all',axis=1)
# 填充缺失值
#1.用0填充
df.fillna(0)
#2.不同的列用不同的值填充
df.fillna({1:0.5, 3:-1})
#3.用均值填充
df.fillna(df.mean())
# 此时axis参数同前面,
将列转成行索引
df.set_index(['col1','col2'...])
数据清洗,重塑
合并数据集
# 取 df1,df2 都有的部分,丢弃没有的# 默认是inner的连接方式
pd.merge(df1,df2, how='inner')
#如果df1,df2的连接字段名不同,则需要特别指定
pd.merge(df1,df2,left_on='l_key',right_on='r_key')
#其他的连接方式有 left,right, outer等。
# 如果dataframe是多重索引,根据多个键进行合并
pd.merge(left, right, on=['key1','key2'],how = 'outer')
#合并后如果有重复的列名,需要添加后缀
pd.merge(left, right, on='key1', suffixes=('_left','_right'))
索引上的合并
#针对dataframe中的连接键不是列名,而是索引名的情况。
pd.merge(left, right, left_on = 'col_key', right_index=True)
#即左边的key是列名,右边的key是index。
#多重索引
pd.merge(left, right, left_on=['key1','key2'], right_index=True)
dataframe的join方法
#实现按索引合并。#其实这个join方法和数据库的join函数是以一样的理解
left.join(right, how='outer')
#一次合并多个数据框
left.join([right1,right2],how='outer')
轴向连接(更常用)
连接:concatenation绑定:binding堆叠:stacking
列上的连接
np.concatenation([df1,df2],axis=1) #np包
pd.concat([df1,df2], axis=1) #pd包
#和R语言中的 cbind 是一样的
#如果axis=0,则和 rbind 是一样的#索引对齐,没有的就为空
# join='inner' 得到交集
pd.concat([df1,df2], axis=1, join='innner')
# keys 参数,还没看明白
# ignore_index=True,如果只是简单的合并拼接而不考虑索引问题。
pd.concat([df1,df2],ignore_index=True)
合并重复数据
针对可能有索引全部或者部分重叠的两个数据集
填充因为合并时索引赵成的缺失值
where函数
#where即if-else函数
np.where(isnull(a),b,a)
combine_first方法
#如果a中值为空,就用b中的值填补
a[:-2].combine_first(b[2:])
#combine_first函数即对数据打补丁,用df2的数据填充df1中的缺失值
df1.combine_first(df2)
重塑层次化索引
stact:将数据转为长格式,即列旋转为行unstack:转为宽格式,即将行旋转为列
result=data.stack()
result.unstack()
长格式转为宽格式
pivoted = data.pivot('date','item','value')
#前两个参数分别是行和列的索引名,最后一个参数则是用来填充dataframe的数据列的列名。如果忽略最后一个参数,得到的dataframe会带有层次化的列。
透视表
table = df.pivot_table(values=["Price","Quantity"],
index=["Manager","Rep"],
aggfunc=[np.sum,np.mean],
margins=True))
#values:需要对哪些字段应用函数#index:透视表的行索引(row)#columns:透视表的列索引(column)#aggfunc:应用什么函数#fill_value:空值填充#margins:添加汇总项
#然后可以对透视表进行筛选
table.query('Manager == ["Debra Henley"]')
table.query('Status == ["pending","won"]')
移除重复数据
# 判断是否重复
data.duplicated()`
#移除重复数据
data.drop_duplicated()
#对指定列判断是否存在重复值,然后删除重复数据
data.drop_duplicated(['key1'])
交叉表
是一种用于计算分组频率的特殊透视表.
注意,只对离散型的,分类型的,字符型的有用,连续型数据是不能计算频率这种东西的。
pd.crosstab(df.col1, df.col2, margins=True)
类似vlookup函数
利用函数或映射进行数据转换
#1.首先定义一个字典
meat_to_animal={
'bacon':'pig',
'pulled pork':'pig',
'honey ham':'cow'
}
#2.对某一列应用一个函数,或者字典,顺便根据这一列的结果创建新列
data['new_col']=data['food'].map(str.lower).map(meat_to_animal)
替换值
data.replace(-999,np.na)
#多个值的替换
data.replace([-999,-1000],np.na)
#对应替换
data.replace([-999,-1000],[np.na,0])
#对应替换也可以传入一个字典
data.replace({-999:np.na,-1000:0})
离散化
#定义分割点
bins=[20,40,60,80,100]
#切割
cats = pd.cut(series,bins)
#查看标签
cats.labels
#查看水平(因子)
cats.levels
#区间计数
pd.value_count(cats)
#自定义分区的标签
group_names=['youth','youngAdult','MiddleAge','Senior']
pd.cut(ages,bins,labels=group_names)
分位数分割
data=np.random.randn(1000)
pd.qcut(data,4) #四分位数
#自定义分位数,包含端点
pd.qcut(data,[0,0.3,0.5,0.9,1])
异常值
#查看各个统计量
data.describe()
#对某一列
col=data[3]
col[np.abs(col)>3]
#选出全部含有“超过3或-3的值的行
data[(np.abs(data)>3).any(1)]
#异常值替换
data[np.abs(data)>3]=np.sign(data)*3
抽样
#随机抽取k行
df.take(np.random.permutation(len(df))[:k])
#随机抽取k行,但是k可能大于df的行数#可以理解为过抽样了
df.take(np.random.randint(0,len(df),size=k))
数据摊平处理
相当于将类别属性转成因子类型,比如是否有车,这个字段有3个不同的值,有,没有,过段时间买,那么将会被编码成3个字段,有车,没车,过段时间买车,每个字段用0-1二值填充变成数值型。
#对摊平的数据列增加前缀
dummies = pd.get_dummies(df['key'],prefix='key')
#将摊平产生的数据列拼接回去
df[['data1']].join(dummies)
字符串操作
# 拆分
strings.split(',')
#根据正则表达式切分
re.split('s+',strings)
# 连接'a'+'b'+'c'...
或者
'+'.join(series)
# 判断是否存在's' in strings`
strings.find('s')
# 计数
strings.count(',')
# 替换
strings.replace('old','new')
# 去除空白字符
s.strip()
正则表达式
正则表达式需要先编译匹配模式,然后才去匹配查找,这样能节省大量的CPU时间。
re.complie:编译findall:匹配所有search:只返回第一个匹配项的起始和结束地址match:值匹配字符串的首部sub:匹配替换,如果找到就替换
#原始字符串
#编译匹配模式,IGNORECASE可以在使用的时候对大小写不敏感
pattern = r'[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}'
regex = re.compile(pattern,flags=re.IGNORECASE)
#匹配所有
regex.findall(strings)
#使用search
m = regex.search(strings) #获取匹配的地址
strings[m.start():m.end()]
#匹配替换
regex.sub('new_string', strings)
根据模式再切分
将模式切分,也就是将匹配到的进一步切分,通过pattern中的括号实现.
pattern = r'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\.([A-Z]{2,4})'
regex = re.compile(pattern)
regex.findall(strings)
#如果使用match
m=regex.match(string)
m.groups()
#效果是这样的
#获取 list-tuple 其中的某一列
matches.get(i)
分组聚合,计算
group_by技术
# 根据多个索引分组,然后计算均值
means = df['data1'].groupby([df['index1'],df['index2']).mean()
# 展开成透视表格式
means.unstack()
分组后价将片段做成一个字典
pieces = dict(list(df.groupby('index1')))
pieces['b']
groupby默认是对列(axis=0)分组,也可以在行(axis=1)上分组
语法糖,groupby的快捷函数
df.groupby('index1')['col_names']
df.groupby('index1')[['col_names']]
#是下面代码的语法糖
df['col_names'].groupby(df['index1'])
df.groupby(['index1','index2'])['col_names'].mean()
通过字典或series进行分组
people = DataFrame(np.random.randn(5, 5),
columns=['a', 'b', 'c', 'd', 'e'],
index=['Joe', 'Steve', 'Wes', 'Jim','Travis'])
# 选择部分设为na
people.ix[2:3,['b','c']]=np.na
mapping = {'a': 'red', 'b': 'red', 'c': 'blue',
'd': 'blue', 'e': 'red', 'f' : 'orange'}
people.groupby(mapping,axis=1).sum()
通过函数进行分组
#根据索引的长度进行分组
people.groupby(len).sum()
数据聚合
使用自定义函数
## 对所有的数据列使用自定义函数
df.groupby('index1').agg(myfunc)
#使用系统函数
df.groupby('index1')['data1']describe()
根据列分组应用多个函数
#分组
grouped = df.groupby(['col1','col2'])
#选择多列,对每一列应用多个函数
grouped['data1','data2'...].agg(['mean','std','myfunc'])
对不同列使用不同的函数
grouped = df.groupby(['col1','col2'])
#传入一个字典,对不同的列使用不同的函数#不同的列可以应用不同数量的函数
grouped.agg({'data1':['min','max','mean','std'],
'data2':'sum'})
分组计算后重命名列名
grouped = df.groupby(['col1','col2'])
grouped.agg({'data1':[('min','max','mean','std'),('d_min','d_max','d_mean','d_std')],
'data2':'sum'})
返回的聚合数据不要索引
df.groupby(['sex','smoker'], as_index=False).mean()
分组计算结果添加前缀
#对计算后的列名添加前缀
df.groupby('index1').mean().add_prefix('mean_')
将分组计算后的值替换到原数据框
#将函数应用到各分组,再将分组计算的结果代换原数据框的值#也可以使用自定义函数
df.groupby(['index1','index2'...]).transform(np.mean)
更一般化的apply函数
df.groupby(['col1','col2'...]).apply(myfunc)
df.groupby(['col1','col2'...]).apply(['min','max','mean','std'])
禁用分组键
分组键会跟原始对象的索引共同构成结果对象中的层次化索引
df.groupby('smoker', group_keys=False).apply(mean)
分组索引转成df的列
某些情况下,groupby的as_index=False参数并没有什么用,得到的还是一个series,这种情况一般是尽管分组了,但是计算需要涉及几列,最后得到的还是series,series的index是层次化索引。这里将series转成dataframe,series的层次化索引转成dataframe的列。
def fmean(df):
"""需要用两列才能计算最后的结果"""
skus=len(df['sku'].unique())
sums=df['salecount'].sum()
return sums/skus
#尽管禁用分组键,得到的还是series
salemean=data.groupby(by=['season','syear','smonth'],as_index=False).apply(fmean)
# 将series转成dataframe,顺便设置索引
sub_df = pd.DataFrame(salemean.index.tolist(),columns=salemean.index.names,index=salemean.index)
# 将groupby的结果和sub_df合并
sub_df['salemean']=salemean
桶分析与分位数
对数据切分段,然后对每一分段应用函数
frame = DataFrame({'col1':np.random.randn(1000),
'col2':np.random.randn(1000)})
#数据分段,创建分段用的因子#返回每一元素是属于哪一分割区间
factor = pd.cut(frame.col1, 4)
#分组计算,然后转成数据框形式
grouped = frame.col2.groupby(factor)
grouped.apply(myfunc).unstack()
用分组的均值填充缺失值
#自定义函数
fill_mean= lambda x:x.fillna(x.mean())
#分组填充
df.groupby(group_key).apply(fill_mean)
分组后不同的数据替换不同的值
#定义字典
fill_value = {'east':0.5, 'west':-1}
#定义函数
fill_func = lambda x:x.fillna(fill_value(x.name))
#分组填充
df.groupby(['index1','index2'...]).apply(fill_func)
sql操作
有时候觉得pandas很方便,但是有时候却很麻烦,不如SQL方便。因此pandas中也有一些例子,用pandas实现SQL的功能,简单的就不说了,下面说些复杂点的操作。
之所以说这个复杂的语句,是因为不想将这些数据操作分写在不同的语句中,而是从头到尾连续编码实现一个功能。
SQL复杂操作用到的主要函数是assign,简单说其实和join的功能是一样的,根据df1,df2的索引值来将df2拼接到df1上。
两个函数是query,也听方便的。
# 有一批销量数据,筛选出那些有2个月以上的销量产品的数据,说白了就是剔除那些新上市产品的数据# 方法是先统计每个产品的数据量,然后选出那些数据量>2的产品,再在数据表中选择这些产品# sku smonth# a 1# a 2# a 3# a 4# b 5# b 6# b 7# b 8# c 9# c 10# 按sku分组,统计smonth的次数,拼接到salecount中,然后查询cnt>2的
salecount.assign(cnt=salecount.groupby(['sku'])['smonth'].count()).query('cnt>2')