您的位置:首页 > 编程语言 > Python开发

用python进行数据分析笔记1--基础知识篇

2017-12-11 15:17 633 查看

前言:

    因为平时的分析工作中常用到的python的一些类库的用户,陆陆续续会作为笔记形式记录下来,也算是给自己做个备忘录。本文聚焦于描述基础用法。

读取CSV文件

直接从JDBC处理,效率太低了,因此对于大数据量的处理,一般是用文件来做的。有一个很大的几个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和columnsDataFrame.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 根据行标签和列标签选择单个值针对seriesobj[['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:匹配替换,如果找到就替换#原始字符串strings = 'sdf@153.com,dste@qq.com,sor@gmail.com'#编译匹配模式,IGNORECASE可以在使用的时候对大小写不敏感pattern = r'[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}'regex = re.compile(pattern,flags=re.IGNORECASE)#匹配所有regex.findall(strings)#使用searchm = 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)#如果使用matchm=regex.match(string)m.groups()#效果是这样的suzyu123@163.com --> [(suzyu123, 163, com)]#获取 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'])# 选择部分设为napeople.ix[2:3,['b','c']]=np.namapping = {'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#尽管禁用分组键,得到的还是seriessalemean=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')
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: