最开始的看到的python基础习题之一,现在顺便扩展一点,练习xlrd、pandas以及matplotlib的练习
数据来源
来自于联通官网的通话数据下载,文件为某年某月的通话记录详情,格式为xls**[图片缺失: 2020/06/QQ截图20200627215145.png]**
使用到的库
import os
import xlrd
import re
from functools import reduce
import pandas as pd
import matplotlib.pyplot as plt
具体方法
使用os.listdir()方法得到所有月份的文件路径,每个路径用xlrd.open_workbook()和workbook.sheet_by_index(0)来获取sheet对象,并使用worksheet.nrows和worksheet.row_values( )[ ]方法获取以及定位内容;
使用正则表达式提取内容中的分秒数据并进行计算,进行插入月份操作后得到一个由月份、总时长、通话次数、平均时长的list对象;
对list对象使用pd.DataFrame(list,index=month,columns=[ '月','总时长(秒)','次数','平均(秒/每次)' ])得到DataFrame对象;
对DataFrame对象使用.plot(x=,y=,kind='bar')和plt.show()方法得到直方图
代码
import os
import xlrd
import re
from functools import reduce
import pandas as pd
import matplotlib.pyplot as plt
class tongxun(object):
def __init__(self,path):
self.path = path
def run(self):
def get_dirs(path):#返回一个由文件完整路径组成的列表
list_=[]
for i in os.listdir(path):
file_path = path + '\\' + i
list_.append(file_path)
return list_
def readxls(path):#从文件中返回一个sheet,输入为文件路径
workbook = xlrd.open_workbook(path)
worksheet = workbook.sheet_by_index(0)
return worksheet
def get_date(worksheet):#从sheet中获取通话时长列表
nrows = worksheet.nrows
time = []
for i in range(nrows):
if i == 0:
pass
else:
time.append(worksheet.row_values(i)[3])
return time
def get_intTime(time_list):#利用正则把分和秒提取出来,输入列表返回列表
time = []
for i in time_list:
s = re.search(r'[0-9]+[分]',i)
if s == None:
m = int(re.search(r'[0-9]+[秒]',i).group().replace('秒',''))
time.append(m)
else:
s_m = int(s.group().replace('分',''))
m = 60*s_m + int(re.search(r'[0-9]+[秒]',i).group().replace('秒',''))
time.append(m)
return time
def get_SumNumAvg(time_all):#实现计算,输入为str列表,返回和、总数、平均的int列表
time = []
time_every = []
for i in time_all:
time.append(get_intTime(i))
for n in time:
time_sum = reduce(lambda x,y:x+y,n)
time_num = len(n)
time_avg = round(time_sum / time_num,1)
time_every.append([time_sum,time_num,time_avg])
return time_every
def insert_month(SumNumAvg):#列表中插入月份
c=1
for i in SumNumAvg:
i.insert(0,c)
c += 1
return SumNumAvg
def get_dateFrame(time_SumNumAvg):#利用列表生成一个dateFrame对象
month = list(range(0,len(time_SumNumAvg)))
df = pd.DataFrame(time_SumNumAvg,index=month,columns=['月','总时长(秒)','次数','平均(秒/每次)'])
return df
#此处运行
time_all = []
for i in get_dirs(self.path):
w=readxls(i)
time_all.append(get_date(w))
time_SumNumAvg = insert_month(get_SumNumAvg(time_all))
data=get_dateFrame(time_SumNumAvg)
while 1:#选择图表类型
input_ = int(input('\n输入你想要的图表(填对应数字):\n1:总时长\n2:次数\n3:平均数\n'))
if input_ == 1:
y_ = '总时长(秒)'
break
elif input_ == 2:
y_ = '次数'
break
elif input_ == 3:
y_ = '平均(秒/每次)'
break
else:
print('输入错误,请重新输入')
data.plot(x='月',y=y_,kind='bar')
plt.show()
if __name__ == "__main__":
y_2020=tongxun(r'C:\Users\14495\Desktop\通信记录')
y_2020.run()
笔记
xlrd是处理文档的库,xlrd.open_workbook()可以得到一个workbook对象(一个xls文件),wordkbook.sheet_by_index()可以以索引的方式得到一个workbook内的sheet对象,使用worksheet.nrows方法得到一个由sheet内每行内容组成的list,使用for循环遍历提取即可
reduce(function,list)方法可对list中每两个紧挨的元素进行function处理,把得到的结果再与下一位元素进行function处理,以此往复得到一个结果。具体为使用匿名函数lambda以及reduce方法进行求和计算。
round(int,1)方法可得到一个保留一位小数的int数字,具体为求平均通话时长中保留一位小数。
list.insert(data,0)方法可在list的0位置上插入data元素,具体为将月份插入list中每一行的开头。
pandas.DataFrame(list_or_dir,index=month,colums=[ '月','总时长(秒)','次数','平均(秒/每次)' ])得到一个由list或dir为数据、索引为month、list每行对应元素为colums一致的dataframe数据对象。
使用DataFrame对象的.plot(x='月',y=' 平均(秒/每次) ',kind='bar')得到以月份为x轴,以平均数为y轴的直方图。
更新6/28
import os
import xlrd
import re
from functools import reduce
import pandas as pd
import matplotlib.pyplot as plt
import tkinter as tk
from tkinter import filedialog
def get_path():
win=tk.Tk()
#filetypes = [('xls files','.xls')]
answer = filedialog.askdirectory(parent=win,initialdir=os.getcwd(),title='选择一个存放通话文件的文件夹(内容为.xls文件)')
print(answer)
return answer
def get_dirs(path):#返回一个由文件完整路径组成的列表
list_=[]
for i in os.listdir(path):
file_path = path + '\\' + i
list_.append(file_path)
return list_
def readxls(path):#从文件中返回一个sheet,输入为文件路径
workbook = xlrd.open_workbook(path)
worksheet = workbook.sheet_by_index(0)
return worksheet
# name = worksheet.name
# nrows = worksheet.nrows
# ncols = worksheet.ncols
def get_date(worksheet):#从sheet中获取通话时长列表
nrows = worksheet.nrows
time = []
for i in range(nrows):
if i == 0:
pass
else:
time.append(worksheet.row_values(i)[3])
return time
def get_intTime(time_list):
time = []
for i in time_list:
s = re.search(r'[0-9]+[分]',i)
if s == None:
m = int(re.search(r'[0-9]+[秒]',i).group().replace('秒',''))
time.append(m)
else:
s_m = int(s.group().replace('分',''))
m = 60*s_m + int(re.search(r'[0-9]+[秒]',i).group().replace('秒',''))
time.append(m)
return time
def get_SumNumAvg(time_all):
time = []
time_every = []
for i in time_all:
time.append(get_intTime(i))
for n in time:
time_sum = reduce(lambda x,y:x+y,n)
time_num = len(n)
time_avg = round(time_sum / time_num,1)
time_every.append([time_sum,time_num,time_avg])
return time_every
def insert_month(SumNumAvg):
c=1
for i in SumNumAvg:
i.insert(0,c)
c += 1
return SumNumAvg
'''
def get_dateFrame(time_SumNumAvg):
month = list(range(1,len(time_SumNumAvg)+1))
w = len(time_SumNumAvg[0])
h = len(time_SumNumAvg)
t = [[0 for b in range(h)]for d in range(w)]
count_2 = 0
for i in time_SumNumAvg:
count_1 = 0
for n in i:
t[count_1][count_2]=n
count_1 += 1
count_2 += 1
df = pd.DataFrame(t,index=['总时长(秒)','次数','平均(秒/每次)'],columns=month)
return df
'''
def get_dateFrame(time_SumNumAvg):
month = list(range(0,len(time_SumNumAvg)))
df = pd.DataFrame(time_SumNumAvg,index=month,columns=['月','总时长(秒)','次数','平均(秒/每次)'])
return df
def run():
path = get_path()
time_all = []
for i in get_dirs(path):
w=readxls(i)
time_all.append(get_date(w))
time_SumNumAvg = insert_month(get_SumNumAvg(time_all))
data=get_dateFrame(time_SumNumAvg)
while 1:#选择图表类型
input_ = int(input('\n输入你想要的图表(填对应数字):\n1:总时长\n2:次数\n3:平均数\n'))
if input_ == 1:
y_ = '总时长(秒)'
break
elif input_ == 2:
y_ = '次数'
break
elif input_ == 3:
y_ = '平均(秒/每次)'
break
else:
print('输入错误,请重新输入')
data.plot(x='月',y=y_,kind='bar')
plt.show()
if __name__ == "__main__":
run()
加入了TK用于文件对话框返回一个路径
由于面向对象写的很烂,暂时先去掉了,之后打算弄个图形界面