数据分析-pandas数据处理清洗常用总结
利用pandas包进行数据分析时常见的操作有:
- 1.创建对象
- 2.查看对象
- 3.选择
- 4.缺失值处理
- 5.相关操作
- 6.合并
- 7.分组和分段
- 8.轴转换和数据透视表
- 9.时间序列
- 10.导入和保存数据
一、创建对象
- 创建Series
- 创建DataFrame
- 查看不同列的数据类型
- 改变索引列名
1.通过传递一个 list 对象来创建一个 Series
s=pd.Series([1,2,3,np.nan,6,8])
s
2.通过传递一个 numpy array,时间索引以及列标签来创建一个 DataFrame
numpy.random.randn()是从标准正态分布中返回一个或多个样本值。
numpy.random.rand()的随机样本位于[0, 1)中。
np.random.randint(0,7,size=10)生成0到7的随机整数
dates=pd.date_range('20130101',periods=6)
df=pd.DataFrame(np.random.randn(6,4),index=dates,columns=list('ABCD'))
df
index和columns也可以在DataFrame创建后指定:
df.index=pd.date_range('20130101',periods=df.shape[0])
df.index=pd.date_range('20130101',periods=len(df))
另外,还可以指定某一列为索引
df = df.set_index('A', drop = True)
通过字典对象来创建一个 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='float32'),
'E':pd.Categorical(['test','train','test','train']),
'F':'foo'})
df2
另外,在原有数据df的基础上,可以创建一个新的数据框df3
df3=pd.dataframe()
df3['min']=df.min()
df3['max']=df.max()
df3['std']=df.std()
df3
或者按行进行汇总统计创建一个新的数据框df4
df4=pd.dataframe()
df4['min']=df.min(axis=1)
df4['max']=df.max(axis=1)
df4['std']=df.std(axis=1)
df4
轴为0的时候是对列的数据进行统计运算,比如shape[0]是行的个数,相当于一个完整的列有多少数据,df.min(axis=0),求每一列的最小值。轴为1是对行的数据量进行统计。
3.查看不同列的数据类型
df2.dtypes
4.改变索引列名
df.rename(index=lambda x:x+5,columns={'A':'newA','B':'newB'})
二、查看数据
- 查看头尾的行数据
- 显示索引、列、底层的数据
- 统计
- 转置
- 按轴排序
- 按值排序
- 查看最大值的索引
- 格式化输出format
1.查看头尾的行数据
df.head()
df.tail(3)
2.显示索引、列、底层的数据
df.index
df.columns
df.values
注意,list(df)显示的是columns
3.统计
查看数据框的行数与列数:(shape[0]是行数shape[1]是列数)
df.shape
查看数据框 (DataFrame) 的索引、数据类型及内存信息:
df.info()
统计每一列非空个数
t.count()
统计某列有多少个不同的类用.nunique()或者len(set()),(统计某列不同类对应的个数用value_counts(),后面相关操作中会提到)
df.A..nunique()
len(set(df.A))
统计某列有哪些不同的类(使用value_counts()也可以显示,同时会显示各个类的个数)
df.A.unique()
统计某列是否有重复数据
df.A.is_unique
对于数据类型为数值型的列,查询其描述性统计的内容:
df.describe()
统计相关系数
df.corr()
4.转置
df.T
5.按轴排序
df.sort_index(0) 按行名排序
df.sort_index(1) 按列名排序
df.sort_index(axis=1,ascending=False)
6.按值排序
按行的值排序:
df.sort_values(by='20130101',axis=1)
按列的值排序:
df.sort_values(by='B')
按顺序进行多列降序排序
df.sort_values(['A','B'],ascending=False)
7.查看最大值的索引
df.idxmax(0) #显示所有列最大值所对应的索引
df.A.idxmax(0) #显示A列中最大值对应的索引
8.格式化输出format
“格式限定符”(语法是'{}'中带:号),可以print相应格式的数据
print('{:.2%}'.format(0.12354))
金额千位分隔符
print('{:,}'.format(123456789))
print('{:.2f}'.format(31.31412))
三、选择
- 直接获取数据
- 通过标签进行选择 .loc[]
- 通过位置进行选择 .iloc[:,:]
- 布尔索引
- 设置赋值
1.直接获取数据(用于获取整行或者整列的数据),此处注意列名一定要大小写对应,否则无法取出数据
df['B']
df.B
选择两列
df[['A','B']]
通过切片获取行数据
df[0:3]
df['20130101':'20130103']
2.通过标签进行选择 .loc[]
标签的优点是可以多轴交叉选择(注意:iloc内部只能单独使用行标签选择行数据,选择某一列标签时前面需加:,):
df.loc[dates[0]]
位置加标签(注意只能用:,不能使用类似0:2的切片):
df.loc[:,['A','B']]
标签加标签:
df.loc['20130101',['A','B']]
获取一个标量:
df.loc['20130101','A']
3.通过位置进行选择 .iloc[:,:]
通过传递数值进行位置选择(选择的是行),特别是选择单行的时候(注意:iloc内部只有一个值得时候是选择的行,选择某一列时列号前面需加:,),另外-1代表最后一列:
df.iloc[3]
选取除了最后三列之外的数据
df.lioc[:,:-3]
通过数值进行切片 位置加位置(区别于loc之处)
df.iloc[1:3,1:3]
通过制定一个位置的列表:
df.iloc[[1,2],[2,3]]
对行、列进行切片:
df.iloc[[0,1],:]
df.iloc[:,[0,1]]
获取特定的值:
df.iloc[1,1]
4.布尔索引
使用一个单独列的值来选择数据:
df[df.A>0]
df[df>0]
选择A列中以a开头的行或列(假设此处的A列是字符串型数据)
df[df.A.str.startswith('a')]
使用 isin()方法来过滤:
df['E']=['one','one','two','there','four','there']
df[df.E.isin(['two','four'])]
5.赋值
①通过标签设置新的值
df.loc['20130101','A']=1
df
如果赋值的标签不存在,则产生新的列(行),未赋值的位置用空值填充
t.loc['20130101','H']=3
t
②通过位置设置新的值
df.iloc[0,0]=2
df
③设置整列值(len可以求表格数据的行数):
df.loc[:,'D']=np.array([3]*len(df))
df
或者
df['D']=np.array([3]*len(df))
df
④通过布尔索引赋值
df2=df.copy()
df2[df2>0]=-df2
df2 #全部转化为负数
四、缺失值处理
- 删除列的方法
- 去掉包含缺失值的行,不改变原来的值
- 对缺失值进行填充
-
对数据进行布尔填充
查看每一列有多少缺失值:
df.isnull().sum()
查看每一列有多少完整的数据
df.shape[0]-df.isnull().sum()
1.删除列的方法:
df.drop(df.columns[4],axis=1,inplace=True) #不知道列名时
df.drop(‘E’,axis=1,inplace=True) #根据列名删除
或
del df['E']
2.去掉包含缺失值的行,不改变原来的值
df.dropna() #不返回df还是原值
df.dropna(how='all') #删除所有均为空值的行
df.dropna(inplace=True) #返回删除后的
移除数据框 DataFrame 中包含空值的列
df.dropna(axis=1)
3.对缺失值进行填充(如果填充后需要保存,需加inplace=True):
df.fillna(value=5)
将所有空值替换为平均值
df.fillna(df.mean())
4.对数据进行布尔填充
pd.isnull(df)
五、相关操作
- 统计行列平均值
- Apply – 对数据应用函数
- 计数 value_counts()
- 字符串大小写转换
- 数据类型转换
- 替换
1.统计行列平均值
按列统计平均
df.mean()
对平均值取整
round(df.mean())
按行统计平均
df.mean(1)
2.Apply – 对数据应用函数
其中注意临时函数lambda的使用
df.apply(lambda x:x.max()-x.min())
df.apply(np.mean) 按行统计axis=1
df.apply(np.max,axis=1)
另外可以通过def 定义函数,再使用apply,例如下面数据的第一列,时间为2061年,存在明显错误,可以通过创建函数去修复这个错误
data = pd.read_table(path6, sep = "\s+", parse_dates = [[0,1,2]])
data.head()
import datetime
def fix_century(x):
year = x.year - 100 if x.year > 1989 else x.year
return datetime.date(year, x.month, x.day)
data['Yr_Mo_Dy'] = data['Yr_Mo_Dy'].apply(fix_century)
data.head()
3.计数 value_counts()
s=pd.Series(np.random.randint(0,7,size=10))
s.value_counts()
DataFrame查看某一列类别数据各类的个数:
df2.E.value_counts()
DataFrame查看所有列的各类统计个数
df2.apply(pd.Series.value_counts)
4.字符串大小写转换
s=pd.Series(['One','Two'])
s.str.lower()
5.将DataFrame的格式转化为浮点数
df.astype(float)
6.替换
df.replace(4,'one')
六、合并
- concat (不通过键值之间的连接)
- merge 类似于 SQL 类型的连接( join)☆
- Append ---- 类似于 SQL 中 union
1.concat (默认上下连接,axis=1时左右连接)
df=pd.DataFrame(np.random.randn(10,4))
df
pieces=[df[:1],df[6:7]]
pd.concat(pieces)
2.merge 类似于 SQL 类型的连接( join)
根据键连接
merge与concat的区别在于,merge需要依据某一共同的行或列来进行合并
left=pd.DataFrame({'key':['foo','foo1'],
'lval':[1,2]})
left
right=pd.DataFrame({'key':['foo','foo2'],
'rval':[4,5]})
right
pd.merge(left,right,on='key')
左连接left,右连接right,外连接outer 默认是inner
pd.merge(left,right,on='key',how='left')
3.Append 将一行连接到一个 DataFrame 上
专门用于上下按照同列名连接---- 类似于 SQL 中 union
append是concat的简略形式,只不过只能在axis=0上进行合并
df=pd.DataFrame(np.random.randn(5,4),columns=list('ABCD'))
df
s=df.iloc[1,:]
df.append(s,ignore_index=True)
七、分组和分段
- 分组(对数据进行分组汇总统计,类似数据透视表)
- 通过多个列进行分组形成一个层次索引
- 分段(对数据进行分段或者分箱切割,可用于连续变量的特征处理,例如woe)
df=pd.DataFrame({'A':['foo','bar','foo','bar','foo','bar','foo','bar'],
'B':['one','two','three','four','two','two','one','three'],
'C':np.random.randn(8),
'D':np.random.randn(8)})
df
1.分组,并对每个分组执行 sum/count/mean/median(中位数)等函数
df.groupby('A').sum()
df.groupby('A').agg(np.sum)
df.groupby('A').agg({'C':sum,'D':sum})
分组求平均值、最大值、最小值
df.groupby('A').C.agg(['mean','max','min'])
按A中类的个数对C求平均值
df.groupby('A').agg({'C':sum})['C'].mean()
2.通过多个列进行分组形成一个层次索引
df.groupby(['A','B']).sum()
3.分段(分箱)
有两种:pd.qcut与pd.cut
按变量取值范围进行均匀分割cut
cut11=pd.cut(df1["可用额度比值"],4)
cut11.head()
按变量个数进行均匀分割qcut
cut11=pd.qcut(df1["可用额度比值"],4)
cut11
cut11=pd.qcut(df1["可用额度比值"],4,labels=False)
cut11.head()
八、轴转换和数据透视表
- Stack堆栈
- 数据透视表
1.Stack堆栈
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','ssecond'])
df=pd.DataFrame(np.random.randn(8,2),index=index,columns=['A','B'])
df
stacked=df.stack()
stacked
stacked2=stacked.unstack()
stacked2
stacked3=stacked2=stacked.unstack(0)
stacked3
stacked4=stacked2=stacked.unstack(1)
stacked4
2.数据透视表
pd.pivot_table()
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
pd.pivot_table(df,values='D',index=['A','B'],columns='C')
df.pivot_table(df,index=['A','B'],columns=['C'],aggfunc=np.sum)
九、时间序列
- 针对时间频率重采样
- 时间类型转换
- 时间采样分组
- 时间筛选问题
1.针对时间频率重采样
首先创建一个采样后的时间序列:
rng=pd.date_range('20120101',periods=61,freq='S')
rng
序列或者索引为时间时,可以使用.resample()重置采样频率
ts=pd.Series(np.random.randint(0,500,len(rng)),index=rng)
ts.resample('1Min',how=sum)
另外采样频率还有:
W weekly frequency
M 每月最后一天
BM 每个月最后一个工作日
2.将int64型数据转化成datetime数据
crime.info()
crime.head()
crime.Year = pd.to_datetime(crime.Year, format='%Y')
crime.info()
crime.head()
3.按时间采样结果分组
例如我们获得一组数据索引是每一年
按如果想按十年进行分组查看数据情况,即进行时间分组求和,可以使用重采样
crimes = crime.resample('10AS').sum()
另外,人口不能按十年的直接相加,使用10年内的最大值汇总,在上述基础上更新population列
population = crime['Population'].resample('10AS').max()
crimes['Population'] = population
4.时间筛选问题
通过创建时间分列字段,进行取样统计计算,此方法优点是配合query可以实现灵活取样
例如,如下,计算每一列一月份的平均值
可以先将时间字段分列,相当于创建了辅助列
data['date'] = data.index
data['month'] = data['date'].apply(lambda date: date.month)
data['year'] = data['date'].apply(lambda date: date.year)
data['day'] = data['date'].apply(lambda date: date.day)
data.head()
再筛选计算
january_winds = data.query('month == 1')
january_winds.loc[:,'RPT':"MAL"].mean()
按年进行取样
data.query('month == 1 and day == 1')
按月取样
data.query('day == 1')
时间差,两个日期之间可以相减,并求对应月数和天数
(data.max() - data.min()).days
十、导入和保存数据
- CSV
- Excel
1.导出
df.to_csv('foo.csv')
df.to_excel('foo.xlsx')
df.to_sql(table_name,connection_object) # 将数据框 (DataFrame)中的数据导入SQL数据表/数据库中
df.to_json(filename) # 将数据框 (DataFrame)中的数据导入JSON格式的文件中
2.导入:
pd.read_csv('foo.csv')
pd.read_excel('foo.xlsx')
pd.read_sql(query, connection_object) # 导入SQL数据表/数据库中的数据
pd.read_json(json_string) # 导入JSON格式的字符,URL地址或者文件中的数据
另外一种常用导入方式
path3 ='../input/pandas_exercise/exercise_data/drinks.csv' #'drinks.csv'
drinks = pd.read_csv(path3)
3.文件导入参数
在读取文件时考虑到格式问题,会使用一些参数进行调整。
参考:https://www.cnblogs.com/datablog/p/6127000.html
sep指定分隔符。如果不指定参数,则会尝试使用逗号分隔。
其中,会用到正则表达式,可以参考:https://baike.baidu.com/item/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/1700215?fr=aladdin
\s ->匹配任何空白字符,包括空格、制表符、换页符等
\f -> 匹配一个换页
\n -> 匹配一个换行符
\r -> 匹配一个回车符
\t -> 匹配一个制表符
\v -> 匹配一个垂直制表符
+->匹配前面的子表达式一次或多次(大于等于1次)。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。
“\s+”则表示匹配任意多个上面的字符。
data = pd.read_table(path6,sep = '\s+')
data.head()
parse_dates 可以将指定的列转化为时间
data = pd.read_table(path6, sep = "\s+", parse_dates = [[0,1,2]])
data.head()