数据分析-pandas数据处理清洗常用总结

96
许辙
0.9 2018.04.12 18:28* 字数 2227

利用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()
数据分析学习
Web note ad 1