欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-03-27 10:33:16
1.导包import pandas as pd2.从csv导入数据pd.read_csvdf=pd.read_csv('file.csv',encoding='utf')3.由现有的两列拼接成一个新的字段A.str.cat(B)brand_supplier=df['brand_name'].str.cat(df['supplier_name'])4.在指定位置插入列|行df.insert(loc, column, value, allow_duplicates=False)df.i...

文章目录

一、读取数据

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