一、openpyxl操作
1 | 复制# 打开带宏的Excel文件,指带xlsm文件 |
一、保存图片,插入图片
1 | 复制# 需要下载模块 |
二、删除某行或某列
1 | 复制wk_sheet.delete_rows(3,2) #删除从第一行开始算的2行内容 |
三、插入行或列
1 | 复制# 插入行,在第一行上面插入三行 |
四、影藏行或列,设置长宽
1 | 复制# 影藏行 |
五、合并拆分单元格
1 | 复制#! 合并的单元格无法二次合并 |
二、pandas操作
1、读取Excel
1 | 复制read_excel(io, sheet_name=0, header=0, skiprows=None, skip_footer=0, index_col=None,names=None, parse_cols=None, parse_dates=False,date_parser=None,na_values=None,thousands=None, convert_float=True, has_index_names=None, converters=None,dtype=None, true_values=None, false_values=None, engine=None, squeeze=False, **kwds) |
io : excel 路径。
sheetname : 返回多表使用sheetname=[0,1],若sheetname=None是返回全表 注意:int/string 返回的是dataframe,而none和list返回的是dict of dataframe
header :指定列名行,默认0,即取第一行,数据为列名行以下的数据 若数据不含列名,则设定 header = None
skiprows : 省略指定行数的数据
skip_footer : 省略从尾部数的int行数据
index_col : 指定列为索引列,也可以使用u”strings”
names : 指定列的名字。
usecols指定读取的列
复制# 将'1,234'读取为'1234'的数字 thousands=','
1
2
3
4
5
6
7
## 2、常见用法
### 1、筛选与取值
复制# 指定第七行为列名
daily_df = pd.read_excel(self.daily_path, header=7)
指定列名
flow_df = pd.read_excel(self.flow_path, names=[‘date’, ‘tp’, ‘flow’, ‘detailed’, ‘visitor_num’])
多条件筛选
data = flow_df[
(flow_df.flow == ‘付费流量’) &
(flow_df.date == date) &
(flow_df.detailed == detailed)
]
高级筛选
all_data = pd.read_excel(self.path, sheet_name=2)
data = all_data[
all_data[‘客户’].map(lambda x: x == ‘四川’) &
all_data[‘商品名称’].map(lambda x: ‘休闲鞋’ in x)
]
print(data)
获取当前对象(dataframe或series)的行列数,已元祖形式返回
data.shape # 返回(3,4)表示当前对象有3行4列数据
取指定列的第一个数:针对series数据
data_invoice[data_invoice[‘订单号’] == Id][‘结算金额’].iloc[0]
获取行(索引值):针对series数据, ser.index[0]
data_source[‘商品名称’].value_counts().index[0]
获取某单元格的数据:针对DataFrame
data.iloc[0, 4]、data.loc[行名, 列名]
serie转DataFrame
pd.DataFrame([serie.to_dict()])
serie转list
data_source[‘商品名称’].to_list()
获取多个列
df[[‘货号’, ‘支付件数’]]
获取某行
data[i:j]
获取某列
data[列名]、data.列名
获取所有行的第一列的数据
pd.values[:, 1]
获取某一列不为空的值
[x for x in info_data[list_columns[0][1]] if str(x) != “nan”]
将dataframe转为list
pd.read_excel(path + ‘/‘ + filename)[0:1].values.tolist()
判断空, df[‘s’] == np.nan
df[‘访客数’].to_list().index(np.nan)
仅获取表头列
[x for x in pd.read_excel(local_path + ‘/download_data/‘ + filename).columns]
转置
df.T
保存不带索引和表头
save_path = ‘C:\Users\LM0060\Desktop\规划数据.xlsx’
dt.T.to_excel(save_path, index=False, header=False)
去调列名那一行后面的空格
stock = pd.read_excel(path, sheet_name=’透视’, header=3)
stock.columns = stock.columns.str.rstrip() # 去掉列名后面空格,会把数值型设为空
stock.columns = stock.columns.map(lambda x: x.rtrip()) # 去掉列名后面空格,更好用
1 |
|
复制planets.drop_duplicates(subset=[‘method’,’year’],keep=’first’,inplace=False)
subset参数是一个列表,可指定多个列名,用于去重的列。
keep的取值有三个:keep=first时,保留相同数据的第一条。keep=last时,保存相同数据的最后一条。 keep=false时,所有相同的数据都不保留。
inplace=True时,会对原数据进行修改。否则,只返回视图,不对原数据修改。
1 |
|
复制# pandas 遍历 dataframe 行数据
for index, row in df.iterrows():
print(index,row[0],row[1],)
pandas 遍历 dataframe 列数据
for x in df.loc[:,’c1’]:
print(x)
1 |
|
复制data_source[‘商品名称’].value_counts()
输出:
DUOZOULU多走路 2022春季男女情侣款国产款时尚透气走路鞋休闲鞋 11
DUOZOULU多走路2021官方冬季新款男女情侣鞋老爹鞋羊毛休闲鞋 7
DUOZOULU多走路 2022春款男女款情侣款舒适透气走路鞋国产鞋休闲鞋跑步鞋 4
1 |
|
复制def date_filtering(datetime_str): # 用于日期选择
dates = str(datetime_str)[1:11].split(‘-‘)
datetime_str = datetime.date(int(dates[0]), int(dates[1]), int(dates[2]))
if Monday <= datetime_str <= Sunday:
return True
else:
return False
data_source = pd.read_excel(self.path, sheet_name=3)
data_source = data_source[
data_source[‘付款确认时间’].map(date_filtering)
]
1 |
|
复制df.drop(index, axis=0),# 是去掉某一行数据;
df.drop(col_name, axis=1),#是去掉某一列的数据?
df.sum(axis=0),# 求每列的数据之和;
df.sum(axis=1),# 求每行的数据之和;
eg:
data_source[‘退款金额’].sum(axis=0)
df[列名].max(axis=0) # 最大值
df[列名].max(axis=0) # 最小值
1 |
|
复制pd.read_csv(inpath, converters={“列名1”:str, “列名2”:str})
1 |
|
复制category = pd.read_excel(path, sheet_name=4)
用前一个不为空的数据填充
category = category.fillna(method=’pad’)
用后一个不为空的数据填充
category.fillna(method=’bfill’,limit=1)
用默认字符填充
category.fillna(‘missing’)
只填充某列,且作用到源数据上,返回None
category[‘Item Sub-Category’].fillna(method=’pad’, inplace=True)
1 |
|
复制# 按某一列的值排序,默认ascending=True升序
df_tm_week.sort_values(‘支付金额’, ascending=False)
按索引排序,下列是取前10
df_tm_week.sort_index()[:10]
1 |
|
复制pds_lin_a.groupby([‘退单编号’])[‘入库数量’].sum()
pds_lin_a.groupby([‘退单编号’]).agg({“入库数量”:”sum”})
1 |
|
复制一、索引转化为列
df[‘index’] = df.index
二、列转化为索引
df.set_index(‘date’)
1 |
|
复制df[‘year’]=df[‘year’].astype(int)
1 |
|
复制”””
rank函数的用法
method参数说明:first:不并次排序:123456、dense:并次不占位排序:123345、min:并次占位排序:123356
“””
pop_RT[‘sort_id’] = pop_RT.groupby([‘model_code_x’])[[‘conception_code’]].rank(ascending=1, method=’dense’)
1 |
|
复制rankings_pd.rename(columns = {‘test’:’TEST’}, inplace = True)
1 |
|
复制# 读取CSV文件,并删除指定行,同时不带表头另存为另一个地址
data = pd.read_csv(open_path + ‘/‘ + filename, header=None) # 读取CSV文件
data.drop(data.index[int(start_row)-1:int(delete_num) + int(start_row)-1], inplace=True)
data.to_csv(save_path + ‘/‘ + filename, index=False, encoding=”utf-8”, header=None)
1 |
|
复制dt.to_csv(folder_path + ‘\‘ + ‘京东快车数据.csv’, encoding=’utf_8_sig’)
1 |
|
复制# 新增列的数据来源
def get_category(df):
try:
return df_main[df_main[‘商家编码13位’].map(lambda x: df[‘货号’][4:] in x)][0:1][‘三级分类’].to_list()[0]
except:
return ‘空’
新增列的名字,axis=1表示新增列,axis=0表示新增行
df_tm_week.loc[:, ‘三级分类’] = df_tm_week.apply(get_category, axis=1)
更简单的方法,新增列来源于自身
this_year_pd.loc[:, ‘折扣前总价’] = this_year_pd[‘发货数量’] * this_year_pd[‘吊牌价’]
分列并去空格
tm_pd.loc[:, ‘一级类目’] = tm_pd[‘京东分类’].str.split(‘>’, expand=True)[0].replace(‘ ‘, ‘’)
1 |
|
复制def data_merge(path, to_file_path):
“””
用于合并数据
:param path: 需要合并的文件夹
:param to_file_path: 合并后的文件保存路径
:return:
“””
filenames = os.listdir(path)
for index, filename in enumerate(filenames):
filepath = path + ‘/‘ + filename
if index == 0: # 第一次,只读取,不合并
pds = pd.read_excel(filepath, header=1)
continue
pds_lin = pd.read_excel(filepath, header=1)
pds = pd.concat([pds, pds_lin])
pds.to_excel(to_file_path, index=False)
1 |
|
复制# how:指定连接方式。可以是inner, outer, left, right,默认为inner。
on:指定连接使用的列(该列必须同时出现在两个DataFrame中),默认使用两个DataFrame中的所有同名列进行连接。
left_on / right_on:指定左右DataFrame中连接所使用的列。
left_index / right_index:是否将左边(右边)DataFrame中的索引作为连接列,默认为False。
suffixes:当两个DataFrame列名相同时,指定每个列名的后缀(用来区分),默认为x与y。
df1=pd.DataFrame({“date”:[2015,2016,2017,2018,2019],”x1”:[2000,3000,5000,8000,10000],”x2”:[np.nan,”d”,”d”,”c”,”c”]})
df2=pd.DataFrame({‘date’:[2017,2018,2019,2020],”y1”:[1000,2000,3000,2000]})
display(df1,df2)
df3=df1.merge(df2,how=’left’,on=”date”)
display(df3)
1 |
|
复制import os
import win32com
from win32com.client import constants as c # 旨在直接使用VBA常数
class CopyTablePaste:
“””
复制表格数据和格式,并粘贴到指定位置,支持复制选定区域的数据、格式、公式
eg:
ctp = CopyTablePaste(‘D:\project\test\测试环境_代码\区域复制.xlsx’)
ctp.copy_style_data(‘复制3’, ‘C6’, ‘C6’)
ctp.paste_style_data(‘复制2’, ‘D6’)
“””
def __init__(self, copy_path, paste_path=None):
"""
初始化,只接受绝对路径
:param copy_path: 需要复制的文件路径
:param paste_path: 需要粘贴的文件路径,默认等同于复制文件
"""
self.xl_app = win32com.client.gencache.EnsureDispatch("Excel.Application") # 若想引用常数的话使用此法调用Excel
self.xl_app.Visible = True # 是否显示Excel文件
self.copy_wb = self.xl_app.Workbooks.Open(copy_path)
if paste_path:
self.paste_wb = self.xl_app.Workbooks.Open(paste_path)
else:
self.paste_wb = self.copy_wb
def copy_style_data(self, sheet_name, start_cell, end_cell, table_path=None):
"""
复制指定表格指定sheet,指定区域的的数据和格式
eg:
copy_style_data("sheet1", "A3", "C5", "D://xx.xlsx")
:param table_path: 读取文件的路径
:param sheet_name: 读取数据的sheet表名
:param start_cell: 读取数据格式的开始单元格
:param end_cell: 读取数据格式的结束单元格
:return:
"""
"""读取文件,如果输入新的文件路径,将替换原有表格"""
if table_path:
self.copy_wb = self.xl_app.Workbooks.Open(table_path)
"""读取文件表"""
sht_old = self.copy_wb.Worksheets(sheet_name)
"""复制选定区域到粘贴板"""
# 对输入的数据进行处理分析
for index, i in enumerate(start_cell):
if not i.isalpha(): # 如果当前字符不是字母,就跳出
break
if not i.isupper():
raise "只接受大写字母"
start_cell = [int(start_cell[index:]), start_cell[:index]]
for index, i in enumerate(end_cell):
if not i.isalpha(): # 如果当前字符不是字母,就跳出
break
if not i.isupper():
raise "只接受大写字母"
end_cell = [int(end_cell[index:]), end_cell[:index]]
rng_data = sht_old.Range(sht_old.Cells(start_cell[0], start_cell[1]), sht_old.Cells(end_cell[0], end_cell[1]))
rng_data.Copy()
def paste_style_data(self, sheet_name, position, table_path=None):
"""
将剪贴板的内容粘贴到指定文件,指定sheet表,的指定位置上
eg:
paste_style_data("sheet2", "A3", "D://xx.xlsx")
:param table_path: 文件路径
:param sheet_name: 文件sheet名
:param position: 粘贴位置
:return:
"""
"""读取文件"""
if table_path:
self.paste_wb = self.xl_app.Workbooks.Open(table_path)
sht_new = self.paste_wb.Worksheets(sheet_name)
"""粘贴到指定区域"""
sht_new.Paste(Destination=sht_new.Range(position)) # 将粘贴板的内容复制到指定区域 √
# sht_new_3.Range("A1").PasteSpecial(Paste=c.xlPasteAll) # 将粘贴板的内容复制到指定区域 √
# sht_new_2.Range("A1").PasteSpecial(Paste=c.xlPasteValues) # 经测试,只能复制数据,无法复制格式 ×
"""保存数据"""
self.paste_wb.Save()
def __del__(self):
"""
当程序运行完成,或者该对象被销毁时程序将自动保存数据,同时关闭电脑上所有的excel文件
:return:
"""
try:
self.copy_wb.Close()
self.paste_wb.Close()
except BaseException as err:
pass
try:
self.xl_app.Quit() # 关闭文件,即使文件已打开也还是会被关闭,如果同时有其它Excel文件打开,也会被关闭
except BaseException as err:
pass
1 |
|
复制def copy_area(self, paste_sh, start_place, end_place, target_place, copy_sh=None, iscpvalue=False):
“””
复制并粘贴某一区域的数据和样式,会在目标位置开始计算结束位置,同时拆分这部分单元格,默认不复制值
:param paste_sh: 用于粘贴的sh源
:param copy_sh: 用于复制的sh源
:param start_place: 开始位置
:param end_place: 结束位置
:param target_place: 目标位置
:param iscpvalue: 是否复制值
:return:
“””
if not copy_sh: # 如果未填写复制源,则表示粘贴复制再同一个sh中
copy_sh = paste_sh
def col_nexts(s, num):
"""获取某一列的后num个对应的列名"""
t = s
for i in range(num):
t = self.col_next(t)
return t
def copy_cell(cy_cell, paste_cell):
"""
复制粘贴单个单元格
:param cy_cell: 需要复制的单元格
:param paste_cell: 需要粘贴的单元格
:return:
"""
if iscpvalue:
try:
paste_sh[paste_cell].value = copy_sh[cy_cell].value # 复制值
except BaseException:
pass
paste_sh[paste_cell].font = copy.copy(copy_sh[cy_cell].font) # 复制:设置字体大小、颜色、下划线等等
paste_sh[paste_cell].border = copy.copy(copy_sh[cy_cell].border) # 复制:设置单元格的边框
paste_sh[paste_cell].fill = copy.copy(copy_sh[cy_cell].fill) # 复制:填充样式
paste_sh[paste_cell].number_format = copy.copy(copy_sh[cy_cell].number_format) # 复制数字格式
paste_sh[paste_cell].protection = copy.copy(copy_sh[cy_cell].protection) # 复制:保护工作表
paste_sh[paste_cell].alignment = copy.copy(copy_sh[cy_cell].alignment) # 复制:单元格对齐
def if_merge(cell): # 判断该单元格是否是合并单元格,如果是,则返回合并的单元格范围
for merge_cell in merge_cell_list:
if cell == merge_cell[0]:
return merge_cell
return False
merge_cell_list = [str(x).split(':') for x in copy_sh.merged_cell_ranges] # 原始sh中的合并单元集合
start_row, start_col = self.analysis_cell(start_place) # 开始位置
end_row, end_col = self.analysis_cell(end_place) # 结束位置
target_row, target_col = self.analysis_cell(target_place) # 目标位置
row_gap = end_row - start_row # 行差
col_gap = self.col_to_num(end_col) - self.col_to_num(start_col) # 列差
# 拆分单元格,将需要粘贴的单元格范围进行拆分,避免出现合并单元格,合并的单元格无法二次合并
try:
paste_sh.unmerge_cells(
range_string=target_place + ':' + col_nexts(target_col, col_gap) + str(target_row + row_gap))
except BaseException:
pass
for x in range(row_gap + 1): # 单元格系统性合并
for y in range(col_gap + 1):
cy_cell = start_col + str(start_row + x)
paste_cell = target_col + str(target_row + x)
if not if_merge(cy_cell): # 如果需要复制的单元格不是合并单元格,则跳过合并
pass
else: # 如果这是一个合并的单元格
merge_range = if_merge(cy_cell) # 得到合并的范围
start_row_x, start_col_x = self.analysis_cell(merge_range[0]) # 开始位置
end_row_x, end_col_x = self.analysis_cell(merge_range[1]) # 结束位置
row_gap_x = end_row_x - start_row_x # 行差
col_gap_x = self.col_to_num(end_col_x) - self.col_to_num(start_col_x) # 列差
merge_cell_start = self.analysis_cell(paste_cell)
merge_cell_end = self.col_nexts(merge_cell_start[1], col_gap_x) + str(merge_cell_start[0] + row_gap_x) # 合并的末尾
paste_sh.merge_cells(range_string='{}:{}'.format(paste_cell, merge_cell_end)) # 进行合并
start_col = self.col_next(start_col)
target_col = self.col_next(target_col)
start_col = self.analysis_cell(start_place)[1]
target_col = self.analysis_cell(target_place)[1]
for x in range(row_gap + 1): # 单元格系统性复制
for y in range(col_gap + 1):
cy_cell = start_col + str(start_row + x)
paste_cell = target_col + str(target_row + x)
try:
copy_cell(cy_cell, paste_cell)
except BaseException as err:
print('复制失败,该单元格可能是合并的单元格')
start_col = self.col_next(start_col)
target_col = self.col_next(target_col)
start_col = self.analysis_cell(start_place)[1]
target_col = self.analysis_cell(target_place)[1]
1 |
|
复制def get_next(s):
“””获取excel某一列的下一列 列名”””
if not s.isalpha(): # 先判断是否全是字母
raise ‘错误的参数’
s = s.upper()
if s[-1] != 'Z':
return s[:-1] + chr(ord(s[-1]) + 1)
if len(s) == sum(map(lambda x: 1 if x == "Z" else 0, s)):
return ''.join(['A' for x in range(len(s) + 1)])
return get_next(s[:-1]) + 'A'
def get_nexts(s, num):
“””获取某一列的后num个对应的列名”””
t = s
for i in range(num):
t = get_next(t)
return t
1 |
|
复制def get_col_num(s):
“””获取指定列对应的列数”””
if not s.isalpha(): # 先判断是否全是字母
raise ‘错误的参数’
s = s.upper()
if len(s) == 1:
return ord(s[-1]) - 64
else:
return get_col_num(s[:-1]) * 26 + ord(s[-1]) - 64
1 |
|
复制def analysis_coordinate(s):
“””解析excel坐标,返回元祖,分别是行和列”””
for i, v in enumerate(s):
if not v.isalpha():
break
col = s[:i].upper()
row = s[i:]
if not col.isalpha() or not row.isdigit(): # 先判断是否全是字母和数字
raise '错误的参数'
return int(row), col
1 |
|
复制def get_num_col(num):
“””获取某一数值对应的列名”””
if num % 26 == 0:
if num == 26:
return ‘Z’
else:
return get_num_col(num // 26 - 1) + ‘Z’
else:
if num < 26:
return chr(64 + num)
else:
return get_num_col(num // 26) + get_num_col(num % 26)
1 |
|
复制def judgemergecell(sh, cell):
“””
判断这个单元格是否是合并的单元格,如果是则返回单元格区间
:param cell:
:param sh:
:return:
“””
mergecells = [x for x in sh.merged_cell_ranges if cell in x]
if len(mergecells) == 0:
return False
else:
str(mergecells[0])
1 |
|
复制import win32com
from win32com.client import constants as c # 旨在直接使用VBA常数
app = win32com.client.Dispatch(‘Excel.Application’) # 若想引用常数的话使用此法调用Excel
app.Visible = True # 使文件打开可见
workbook = app.Workbooks.Open(flag, None, True) # 以只读方式显示打开文件
```