当前位置: 移动技术网 > IT编程>脚本编程>Python > 【Python数据科学速查】Pandas等常用操作应用替代于excel数据整理

【Python数据科学速查】Pandas等常用操作应用替代于excel数据整理

2020年07月11日  | 移动技术网IT编程  | 我要评论

文章目录

一、读取数据

1.导包
import pandas as pd
2.从csv导入数据

pd.read_csv()

df=pd.read_csv('file.csv',encoding='utf')

如果文件名带中文,上述方法可能报初始化错误,使用以下方法:
f=open('文件.csv')wirh open('文件.csv') as f:
df = pd.read_csv(f)

with open('文件.csv',encoding='utf-8') as f:
    df=pd.read_csv(f)
3.从excel导入文件

pd.read_excel(file.xlsx')

df_order=pd.read_excel('file名.xlsx')

该方法接受文件名带中文

二、字段(列)|索引的属性更改

1.针对某(些)个字段(列)|索引更名

df.rename(mapper=None, index=None, columns=None, axis=None, copy=True, inplace=False, level=None)

df_order.rename(columns={'下单日期':'日期','下单小时':'小时'},inplace=True)
或
df_order.rename({'下单日期':'日期','下单小时':'小时'},axis='columns',inplace=True)
#inplace=True对原dataframe进行修改

该方法可以更改列名或行名或更改标签值类型
如果需要改的列名特别多,可以直接给df的columns属性赋值,修改全部列名

df.columns=['年','周','频道','性别','销售数量','销售金额']

三、行列的结构变动

1.在指定位置插入行
STEP1:分割
df=pd.DataFrame([list('abc'),list('anf'),list('abc'),list('fgc'),list('rbc')])
df_p1=df[:2]
df_p2=df[2:]
STEP2:添加——底部追加内容

df.append(other, ignore_index=False, verify_integrity=False, sort=None)

ser_m=pd.Series([44,55,66])
df_p1=df_p1.append(ser_m,ignore_index=True)
STEP3:合并——多个dataframe堆叠

pd.concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False, sort=None, copy=True)
该方法不仅可以上下堆叠,还可以左右堆叠

df=df_p1.append(df_p2,ignore_index=True)
或
df=pd.concat([df_p1,df_p2],ignore_index=True]
2.在指定位置插入列

df.insert(loc, column, value, allow_duplicates=False)

df.insert(7,'brand_supplier',brand_supplier)

插入的列除了源dataframe结构的序列,也可以是常量,或者空值np.nan

3.一般方法删除指定行或列(按照索引或列名)

(1). 先获取索引,再使用drop方法删除

STEP1:获取记录index

df[条件序列].index
ser[条件序列].index

del_index=df[df['subcategory'].isin(list_type)].index
ser_nor[ser_nor>1].index
STEP2:删除索引所在行

df.drop(labels=None, axis=0, index=None, columns=None, level=None, inplace=False, errors='raise')
其中:axis=0代表行,axis=1代表列

df.drop(del_index,axis=0,inplace=True)

(2). 如果条件不复杂,条件取反后赋值给原df

df=df.query('ID!=12123')
df
4.调整列序

如果仅调整某列的位置,可以取出-删除-插入

df_id = df.id
df = df.drop('id',axis=1)
df.insert(0,'id',df_id)

如果要调整的列比较繁杂,可以直接定义好列序,赋值给原df即可

df=df[['姓名','年龄','工号']]
5.去除重复记录

去除重复记录,可以用删除的一般方法,先用duplicated()找到重复数据的索引,再drop删除,也可以直接使用:
df.drop_duplicates(subset=None, keep='first', inplace=False)

6.删除空行|空列

df.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)

7.连接merge

merge操作类似于excel中vlookup的存在,在sql中效通join,一般会伴随这字段的新增或更改。
df.merge(right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=False, suffixes=('_x', '_y'), copy=True, indicator=False, validate=None)

df=df1.merge(right=df2,how='left',on=['店铺名称','日期','小时'])
8、透视

df.pivot_table(values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All')

df_pv_pivot=df_pv.pivot_table(index=['资讯ID','日期'],values='PV',aggfunc='sum')

参考: https://blog.csdn.net/weixin_40844116/article/details/105802193

四、按照列条件筛选记录

选取数据的方法有很多种,本节简单使用df[条件]选取符合条件的行记录,列全部保留。
实际操作中使用索引器loc\iloc可以灵活选取所需数据,包括列的选择,例如

df[df['ID']==12121].iloc[:,2:5]#df[条件].iloc[:,列号:列号]

等价于掩码操作

df.loc[df['ID']==12121,'标题':'编辑']#df.loc[条件,列名:列名]

也可以使用df.query()方法取,适用于运算条件,例如:

df.query('ID==12121').loc[:,'标题':'编辑']#df.query(字符串表达式).loc[:,列名:列名]

参考 https://blog.csdn.net/weixin_40844116/article/details/105372173
参考 https://blog.csdn.net/weixin_40844116/article/details/107221706

1.单列条件筛选记录
1).筛选某列包含某字符串的记录

df[df[列名].str.contains(正则表达式)]

df[df['brand_supplier'].str.contains('.*华鼎.*')]
2).从某列筛选等于|不等于某值的记录

df[df[列名]==值]
df[df[列名]!=值]

df[df['shop_name']=='XXXTRENTA']
df[df['shop_name']!='XXXTRENTA']
3).从某列筛选等于|不等于某些值的记录

df[df[列名].isin(列表)]
df[~df[列名].isin(列表)]

list_type=['运动','美妆','男装','女装']
df[df['subcategory'].isin(list_type)]
df[~df['subcategory'].isin(list_type)]
4).找到重复的记录 | 非重复的记录-提取汇总项

(同样的记录第一次出现是非重复,之后又出现的都算重复)
df[df.duplicated(subset=None, keep='first')]
df[~df.duplicated(subset=None, keep='first')]
subset是列名或列名集合,用它来定义重复,缺失默认全字段重合的数据才是重复。

#重复的记录
df_passenger[df_passenger.duplicated('店铺名称')]
#非重复的记录
df_passenger[~df_passenger.duplicated('店铺名称')]

EXTEND:
如果要提取汇总项,除了上述方法找到非重复记录后取该列,

df_passenger[~df_passenger.duplicated('店铺名称')]['店铺名称']#pandas.core.series.Series

也可以用分组groupby汇总项索引转列后提取使用

df_passenger.groupby(by='店铺名称').count().reset_index()['店铺名称']#pandas.core.series.Series

或者df[列名].unique()——最快捷

df_passenger['店铺名称'].unique()#numpy.ndarray

甚至可以对汇总项快速计数df[列名].value_counts()

df_passenger['店铺名称'].value_counts()#pandas.core.series.Series
5).找到空值记录

df[pd.isna(df[列名])]等价于df[pd.isnull(df[列名])]

df[pd.isna(df['name'])]
2.多个列组合筛选

与:df[(条件列筛选序列1)&(条件列筛选序列2)]
或:df[(条件列筛选序列1)|(条件列筛选序列2)]
异或:df[(条件列筛选序列1)^(条件列筛选序列2)]

df[(df['brand_supplier'].str.contains('.*华鼎.*'))&(df['shop_name']!='XXXTRENTA')]

五、列的值处理

1.填充空值

单列填充空值df[列名].fillna(值)
全表填充空值df.fillna(值)

df['subcategory'].fillna('其它')
2.单列赋值

df[列名]=值
这里的值可以是函数应用公式(见第七节),也可以是常量

df['channel']='淘宝'
2.替换单个值和批量替换值

(1)单值替换
方法1:定位要替换的值后直接赋替换后的值:df.loc[df[列名]==被替换的值,列名]=值

df.loc[df['subcategory']=='关店','subcategory']='其它'

方法2:replace方法df.replace(to_replace=None, value=None, inplace=False, limit=None, regex=False, method='pad')

df['subcategory']=df['subcategory'].replace('关店','其它')

(2)批量替换

  • 一对一
#方法一:使用列表,保证顺序对应
xlist=['A','B','C']
ylist=['a','b','c']
#for o,l in zip(xlist,ylist):
#	df[列名]=df[列名].replace(o,l)
df[列名].replace(xlist,ylist,inplace=True)
#方法二:使用字典
mapdict={'A':'a','B':'b','C':'c'}
#for m in maplist:
#	df[列名]=df[列名].replace(m,mapdict[m])
df[列名].replace(mapdict)
  • 多对一
#条件查找,模糊替换
df.loc[pd.to_numeric(df_pp.loc[:,'年季'].str[0:2])<=17,'年季']='17年以前'
#确值替换
df['姓名'].replace(['张倩','张茜'],'张芊')
3.类型转换:日期-数值-字符串转换

主要方法有:

  • pandas内置函数、
  • 自定义函数、
  • numpy中的强制类型交换方法astype(dtype, order='K', casting='unsafe', subok=True, copy=True)
    | b boolean
    | i signed integer
    | u unsigned integer
    | f floating-point
    | c complex floating-point
    | m timedelta
    | M datetime
    | O object
    | S (byte-)string
    | U Unicode
    | V void
    参考:https://www.jb51.net/article/175212.htm
1)字符串类型的数据,转换成日期

对于形似日期的字符串数据,可以转换成真正的日期

  • 对于单个数据:
    from dateutil import parser
    parser.parse(string)
from dateutil import parser
date=parser.parse('2020-6-1')
date
>>>datetime.datetime(2020, 6, 1, 0, 0)
  • 对于pandas序列:
    pd.to_datetime(df[列名])
pd.to_datetime(df_order['日期'],format="%Y-%m-%d")#这里format是传入的格式

或者
df[列名].astype('M')datetime64[ns]

2)日期转成指定样式的字符串
  • 对于单个数据:
    date.strftime(样式)
date.strftime("%Y%m%d")
>>>'20200601'
#获取当天日期
import time
time.strftime('%Y%m%d')
#或者
import datetime
datetime.date.today().strftime('%Y%m%d')

  • 对于pandas序列,没有直接的转换方法,需要使用函数转换
    df[列名].apply(lambda x:x.strftime(指定格式))
pd.to_datetime(df_order['日期']).apply(lambda x:x.strftime("%Y%m%d"))
或者
def dtos(x):
    return x.strftime("%Y%m%d")
pd.to_datetime(df_order['日期']).apply(dtos)
3)字符串转数值
  • 对于单个数据,直接int(string)即可
  • 对于pandas序列
    pd.to_numeric(df[列名])
df_order['日期']=pd.to_numeric(pd.to_datetime(df_order['日期']).apply(lambda x:x.strftime("%Y%m%d")))

或者
df[列名].astype('int')int32

4)数值转字符串
  • str(number)
df_order['年龄'].apply(lambda x:str(x))

或者
df[列名].astype('str')object

六、字符串类型列的字符内容的处理

这里是对字符串值的字符内容的处理,与字段内容处理不同,例如替换值,excel里面是ctrl+h,python里参考本文,可以用df[A].replace()方法;
而本节是针对字符串内容的处理,在excel中替换字符用的是substitute函数,python里面需要df[A].str.replace()

  • 查看这些内置方法:help(pd.Series.str)阅读英文帮助文档
  • 参考文档:https://blog.csdn.net/qq_28219759/article/details/52919233
1.由现有的两列拼接成一个新的字段

df[A].str.cat(df[B])

brand_supplier=df['brand_name'].str.cat(df['supplier_name'])
2.查找子串在字符值中的位置

df[A].str.find(childstring)

df['店铺名称'].str.find('餐厅')
3.返回指定位置的字符

返回单个字符df[A].str.get(index)

df['店铺名称'].str.get(0)

返回片段用切片

df['店铺名称'].str[:3]
4.判断字符值中是否包含子串

df[A].str.contains(childstring)

df['店铺名称'].str.contains('餐厅')
5.计算子串在字符值中的出现次数

df[A].str.count(childstring)

df['店铺名称'].str.count('餐厅')
6.替换字符值中的子串

df[A].str.replace(原字符,后字符)

df['姓名'].str.replace('三','二')#将‘三替’换成‘二’

字符串中的replace一般只可以一个字符串对应一个字符串替换,不能是列表或字典。

7.根据字符分割整字符串,再截取子串

df[A].str.split(childstring)

df['姓名'].str.split('三').str[-1]
8.其它字符串功能使用函数

除了str内置方法,也可以根据需求定制处理函数,通用的函数方法具体见下节。

1)根据字符分割整字符串,截取子串

split()分割字符串,分割后生成子字符串列表,根据列表索引选择要截取的部分

df['姓名'].apply(lambda x:x.split('三')[-1])
2)字符大小写

小写lower()大写upper()

df_passenger['店铺名称'].apply(lambda x:x.lower())
df_passenger['店铺名称'].apply(lambda x:x.upper())

七、构建函数公式计算字段

上一节字符内容的处理也是计算字段,包括转换类型部分也涉及到。本节介绍更通用的函数方法处理字段值。
要传入的计算对象.apply(func, axis=0, broadcast=None, raw=False, reduce=None, result_type=None, args=(), **kwds)
要传入的对象可以是df,也可以是series、groupbySeries
func可以是匿名函数或者自定义函数

1.函数写法

(1).匿名函数

df['ID'].apply(lambda x: 'Boy' if x>30000 else 'Girl')

(2).自定义函数

  • 传入series
def compare(x):
    if x>30000:
        y='Boy'
    else:
        y='Girl'
    return y
df['ID'].apply(compare)#传入series
  • 传入df,指定方向
def dfcompare(x):
    if x['ID']>30000:
        y='Boy'
    else:
        y='Girl'
    return y
df.apply(dfcompare,axis=1)#传入df,axis=1指定逐行

extend:applymap()函数,可以使公式应用于所有元素,不用指定行列方向

2.公式写法

参考 https://blog.csdn.net/weixin_40844116/article/details/107221706
常规:

#(入库金额-退供应商金额)*90天售罄/100
df_sq['收入']=(df_sq['销售']-df_sq['退货'] )* df_sq['90天均价']/100

df.eval():

nisq=df_sq['90天均价']
df_sq['收入']=df_sq.eval('(销售-退货)*@nisq/100')
#列名不规范,可以先定义变量
#df_sq['收入']=df_sq.eval('(销售-退货)*90天均价/100')
#报错,不能直接使用带数字的不规范列名

pd.eval():

#df_sq['收入']=pd.eval("(df_sq.销售-df_sq.退货 )*df_sq.90天均价/100")
#报错,【df_sq.90天均价】写法错误

八、分组

1.分组

df.groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=False, observed=False, **kwargs)

df.groupby(by=['brand_supplier','shop_name'])
2.分组聚合计算

DataFrameGroupBy.函数()

df.groupby(by=['brand_supplier','shop_name']).sum()
3.取指定列来分组聚合计算/分组聚合计算后取指定列

DataFrameGroupBy.函数()[列名]/
DataFrameGroupBy[列名].函数()

ser_nor=df_nor.groupby('brand_supplier').count()['shop_name']
或者
ser_nor=df_nor.groupby('brand_supplier')['shop_name'].count()

九、索引——列的转换

1.索引转列

groupby后,by字段会变成index,如果需要转成正常列,操作如下
索引转列reset_index()

df_nor=df.groupby(by=['brand_supplier','shop_name']).sum().reset_index()
#'brand_supplier','shop_name'原本是index,转成正常列侯,也由Series变成了dataframe
2.列转索引

列转索引set_index()

十、文件存储

1.保存到excel

pd.to_excel()
ser.to_excel()

 ser[ser!=0].to_excel('G:\\work files\file.xlsx',encoding='utf')
 df[df['amount']!=0].to_excel('G:\\work files\file.xlsx',encoding='utf')
2.同一文件夹文件重名时增序命名
impoert os
filepath='文件存放路径'
newfile_name='带后缀的完整文件名'
i=0
while newfile_name in os.listdir(filepath):#如果当前路径已经存在文件
    i=i+1#指定增序
    newfile_name='文件名'+'('+str(i)+')'+'.xlsx'#要保存的文件重命名:在文件名后加序号
#循环至没有同名文件
newfile=filepath+'\\'+ newfile_name#要保存的完整路径文件名

df.to_excel(newfile,index=None)

CASE

插入拼接列
并剔除有多个shop_name的brand_supplier重复数据

import sys
def main(inda):
    import pandas as pd
    
    df=pd.read_csv('G:\\temp files\\file.csv',encoding='utf')

    #插入新字段
    brand_supplier=df['brand_name'].str.cat(df['supplier_name'])#拼接两个字段成一个新字段
    df.insert(7,'brand_supplier',brand_supplier)#插入新字段到dataframe

    #删除“华鼎”系列重复项
    del_col=df[(df.brand_supplier.str.contains('.*华鼎.*'))&(df.shop_name!='XXXTRENTA')].index#获取要删除数据的索引号(品牌供应商名包含“华鼎”且店铺不为"XXXTRENTA")
    df.drop(del_col,axis=0,inplace=True)#删除获得的索引号所在行记录

    #获得有重复店铺数据的品牌供应商
    df_nor=df.groupby(by=['brand_supplier','shop_name']).sum().reset_index()#多维度分组,随意指定一个计算行数sum(),方便将index'brand_supplier','shop_name'转为DataFrame普通列
          
    ser_nor=df_nor.groupby('brand_supplier').count().shop_name#取到分组序列,索引号是分组依据字段'brand_supplier'
    dup_list=list(ser_nor[ser_nor>1].index)#筛选计数大于1即店铺有多个的'brand_supplier'的列表


    #删除多余店铺
    for bs in dup_list:
        shnm_list=list(df[df.brand_supplier==bs].groupby('shop_name').count().reset_index().shop_name)#多店铺的brand_supplier下的各shop_name列表
        brnm=df[df.brand_supplier==bs].brand_name.iloc[0]#brand_supplier对应的brand_name(唯一),所以只要取一个就行

        #逻辑:如果多个店铺名中至少有跟品牌同名的,那就将该brand_supplier下店铺名不等于品牌的数据删掉(保留店铺名与品牌有同名关系的店铺)
        if brnm.lower() in [shlw.lower() for shlw in shnm_list]:#忽略大小写需要同时转大写或小写才能比较
            for sn in shnm_list:#将shop_name和brand_name对比
                if sn.lower()!=brnm.lower():#如果shop_name和brand_name不能完全相等
                    del_col_sh=df[(df.brand_supplier==bs)&(df.shop_name==sn)].index#那就找到该brand_supplier下的该shop_name
                    df.drop(del_col_sh,axis=0,inplace=True)#删除
        #逻辑:如果店铺名没有一个与品牌名同名,那就只保留subcategory不为空的店铺
        else:
            list_type=['运动','美妆','男装','女装'']

            del_col_su=df[(df.brand_supplier==bs)&(~df['subcategory'].isin(list_type))].index#找到该brand_supplier下subcategory不为列表中项的数据,就是subcategory空
            df.drop(del_col_su,axis=0,inplace=True)
            
                
    #导出所需透视图
    df.subcategory=df.subcategory.fillna('其它')#空值和关店改成其它
    df.loc[df.subcategory=='关店','subcategory']='其它'

    ser=df.groupby(['shop_name','subcategory']).sum().amount#df.groupby(['shop_name','subcategory'])['amount'].sum()
    ser[ser!=0].to_excel('G:\\work files\\file'+str(inda)+'.xlsx',encoding='utf')#取值为不为0的项

        
if __name__=='__main__':
    main(sys.argv[1])

本文地址:https://blog.csdn.net/weixin_40844116/article/details/107041313

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网