zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。
zip 方法在 Python 2 和 Python 3 中的不同:在 Python 3.x 中为了减少内存,zip() 返回的是一个对象。如需展示列表,需手动 list() 转换。
zip 语法:
zip([iterable, ...])
参数说明:
返回元组列表。
以下实例展示了 zip 的使用方法:
>>>a = [1,2,3]
>>> b = [4,5,6]
>>> c = [4,5,6,7,8]
>>> zipped = zip(a,b) # 打包为元组的列表
[(1, 4), (2, 5), (3, 6)]
>>> zip(a,c) # 元素个数与最短的列表一致
[(1, 4), (2, 5), (3, 6)]
>>> zip(*zipped) # 与 zip 相反,*zipped 可理解为解压,返回二维矩阵式
[(1, 2, 3), (4, 5, 6)]
zip
打包为元组的列表
unzip
与 zip 相反,*zipped 可理解为解压,返回二维矩阵式
zip(* matrix[1:])
相当于矩阵转置
strs.sort(key = functools.cmp_to_key(sort_rule))
def sort_rule(x, y):
a, b = x + y, y + x
if a > b: return 1
elif a < b: return -1
else: return 0
strs.sort(key = functools.cmp_to_key(sort_rule))
'00'<=num[i-1:i+1]<='09'
✅
'0'<=num[i-1:i+1]<='9'
❌
ord(‘a’) == 65
chr(65) == ‘a’
str=input(‘输入大写字母:’)
chr(ord(str)+32)) #先将字符通过ord函数转换成ASCII码,然后+32从大写变成小写(小变大-32),再通过chr函数转换成字符
print( chr(ord(‘1’)+3))#现将字符1转换成ASCII码,再+3后装换回字符
输出结果:4
如:
>>> '0' <= '1A' <= '99'
True
Python可视化 | Seaborn5分钟入门(七)——pairplot
pairplot主要展现的是变量两两之间的关系(线性或非线性,有无较为明显的相关关系),照例来总览一下pairplot的API。
seaborn.pairplot
(data, hue=None, hue_order=None, palette=None, vars=None, x_vars=None, y_vars=None, kind=‘scatter’, diag_kind=‘auto’, markers=None, height=2.5, aspect=1, corner=False, dropna=True, plot_kws=None, diag_kws=None, grid_kws=None, size=None)
Plot pairwise relationships in a dataset.
kind:用于控制非对角线上的图的类型,可选“scatter”与“reg”
diag_kind:控制对角线上的图的类型,可选“hist”与“kde”
hue
:针对某一字段进行分类
palette
:控制色调
markers
:控制散点的样式
n 折交叉验证, 按照比例选择索引
# n 折交叉验证
>>> import numpy as np
>>> from sklearn.model_selection import KFold
# >>> X = np.array([[1, 2], [3, 4], [1, 2], [3, 4]])
>>> X = np.array([[1, 1], [2, 2], [3, 3], [4, 4], [4, 4]])
>>> y = np.array([1, 2, 3, 4,5])
>>> kf = KFold(n_splits=5)
>>> kf.get_n_splits(X)
print(kf)
>>> for train_index, test_index in kf.split(X):
... print("TRAIN:", train_index, "TEST:", test_index)
... X_train, X_test = X[train_index], X[test_index]
... y_train, y_test = y[train_index], y[test_index]
out
KFold(n_splits=5, random_state=None, shuffle=False)
TRAIN: [1 2 3 4] TEST: [0]
TRAIN: [0 2 3 4] TEST: [1]
TRAIN: [0 1 3 4] TEST: [2]
TRAIN: [0 1 2 4] TEST: [3]
TRAIN: [0 1 2 3] TEST: [4]
numpy中的ravel()、flatten()、squeeze()都有将多维数组转换为一维数组的功能,区别: ravel():如果没有必要,不会产生源数据的副本 flatten():返回源数据的副本 squeeze():只能对维数为1的维度降维
print("数据类型",type(a1)) #打印数组数据类型
print("数组元素数据类型:",a1.dtype) #打印数组元素数据类型
print("数组元素总数:",a1.size) #打印数组尺寸,即数组元素总数
print("数组形状:",a1.shape) #打印数组形状
print("数组的维度数目",a1.ndim) #打印数组的维度数目
在日常的数据处理中,经常会对一个DataFrame
进行逐行、逐列和逐元素的操作,对应这些操作,Pandas中的map
、apply
和applymap
可以解决绝大部分这样的数据处理需求。
save_model = './bert.bin'
"""
如果: 模型在验证集效果比最佳的好,则保存模型
否则, early_stop+=1,
如果early_stop`3:停止训练
"""
def train(self):
logging.info('Start training...')
for epoch in range(1, epochs + 1):
train_f1 = self._train(epoch)
dev_f1 = self._eval(epoch)
if self.best_dev_f1 <= dev_f1:
logging.info(
"Exceed history dev = %.2f, current dev = %.2f" % (self.best_dev_f1, dev_f1))
torch.save(self.model.state_dict(), save_model)
self.best_train_f1 = train_f1
self.best_dev_f1 = dev_f1
self.early_stop = 0
else:
self.early_stop += 1
if self.early_stop ` early_stops:
logging.info(
"Eearly stop in epoch %d, best train: %.2f, dev: %.2f" % (
epoch - early_stops, self.best_train_f1, self.best_dev_f1))
self.last_epoch = epoch
break
"""测试函数, 加载保存的模型并使用验证函数"""
def test(self):
self.model.load_state_dict(torch.load(save_model))
self._eval(self.last_epoch + 1, test=True)
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)-15s %(levelname)s: %(message)s')
logging.info("Use cuda: %s, gpu id: %d.", use_cuda, gpu)
collections
- 容器数据类型namedtuple() |
创建命名元组子类的工厂函数 |
---|---|
deque |
类似列表(list)的容器,实现了在两端快速添加(append)和弹出(pop) |
ChainMap |
类似字典(dict)的容器类,将多个映射集合到一个视图里面 |
Counter |
字典的子类,提供了可哈希对象的计数功能 |
OrderedDict |
字典的子类,保存了他们被添加的顺序 |
defaultdict |
字典的子类,提供了一个工厂函数,为字典查询提供一个默认值 |
UserDict |
封装了字典对象,简化了字典子类化 |
UserList |
封装了列表对象,简化了列表子类化 |
UserString |
封装了列表对象,简化了字符串子类化 |
c = Counter() # a new, empty counter
c = Counter('gallahad') # a new counter from an iterable
c = Counter({'red': 4, 'blue': 2}) # a new counter from a mapping
c = Counter(cats=4, dogs=8) # a new counter from keyword args
>>> for a in c.items():
... print(a)
...
('red', 2)
('blue', 3)
('green', 1)
>>> for a in c.elements():
... print(a)
...
red
red
blue
blue
blue
green
elements
()
返回一个迭代器,其中每个元素将重复出现计数值所指定次。 元素会按首次出现的顺序返回。 如果一个元素的计数值小于一,elements()
将会忽略它。>>>>>> c = Counter(a=4, b=2, c=0, d=-2) >>> sorted(c.elements()) ['a', 'a', 'a', 'a', 'b', 'b']
most_common
([n])
返回一个列表,其中包含 n 个最常见的元素及出现次数,按常见程度由高到低排序。 如果 n 被省略或为 None
,most_common()
将返回计数器中的 所有 元素。 计数值相等的元素按首次出现的顺序排序:>>>>>> Counter('abracadabra').most_common(3) [('a', 5), ('b', 2), ('r', 2)]
subtract
([iterable-or-mapping])
从 迭代对象 或 映射对象 减去元素。像 dict.update()
但是是减去,而不是替换。输入和输出都可以是0或者负数。>>>>>> c = Counter(a=4, b=2, c=0, d=-2) >>> d = Counter(a=1, b=2, c=3, d=4) >>> c.subtract(d) >>> c Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})
3.2 新版功能.
通常字典方法都可用于 Counter
对象,除了有两个方法工作方式与字典并不相同。
fromkeys
(iterable)
这个类方法没有在 Counter
中实现。
update
([iterable-or-mapping])
从 迭代对象 计数元素或者 从另一个 映射对象 (或计数器) 添加。 像 dict.update()
但是是加上,而不是替换。另外,迭代对象 应该是序列元素,而不是一个 (key, value)
对。
append
(x)
添加 x 到右端。
appendleft
(x)
添加 x 到左端。
clear
()
移除所有元素,使其长度为0.
copy
()
创建一份浅拷贝。3.5 新版功能.
count
(x)
计算 deque 中元素等于 x 的个数。3.2 新版功能.
extend
(iterable)
扩展deque的右侧,通过添加iterable参数中的元素。
extendleft
(iterable)
扩展deque的左侧,通过添加iterable参数中的元素。注意,左添加时,在结果中iterable参数中的顺序将被反过来添加。
index
(x[, start[, stop]])
返回 x 在 deque 中的位置(在索引 start 之后,索引 stop 之前)。 返回第一个匹配项,如果未找到则引发 ValueError
。3.5 新版功能.
insert
(i, x)
在位置 i 插入 x 。如果插入会导致一个限长 deque 超出长度 maxlen 的话,就引发一个 IndexError
。3.5 新版功能.
pop
()
移去并且返回一个元素,deque 最右侧的那一个。 如果没有元素的话,就引发一个 IndexError
。
popleft
()
移去并且返回一个元素,deque 最左侧的那一个。 如果没有元素的话,就引发 IndexError
。
remove
(value)
移除找到的第一个 value。 如果没有的话就引发 ValueError
。
reverse
()
将deque逆序排列。返回 None
。3.2 新版功能.
rotate
(n=1)
向右循环移动 n 步。 如果 n 是负数,就向左循环。如果deque不是空的,向右循环移动一步就等价于 d.appendleft(d.pop())
, 向左循环一步就等价于 d.append(d.popleft())
。
Deque对象同样提供了一个只读属性:
maxlen
Deque的最大尺寸,如果没有限定的话就是 None
。
终止线程的方法我采取的方案是利用全局实时变化的变量标志位进行判断终止。
在比较复杂的工程中会存在Python跨文件全局变量的使用
python跟C不一样,c是在一个文件定义后在另一个文件声明下是extern变量就好。python则是通过global声明,但作用域依旧是单个文件。
有一种方式是在A定义,在B import。这种方式,如果仅存在B import A ,那没问题。但是如果A又存在import B则会报错,原因是出现循环调用。解决办法也有几种,这里不展开。这种方式,有一个问题,就是无法实时传递变量,B import后,A中发生了变化,B是不知道的。
于是乎,不如单独拿一个py文件来单独存放这些全局变量,其他文件都可以单向import。
单独搞一个global_var.py如下:
# -*- coding: utf-8 -*-
def _init(): # 初始化
global _global_dict
_global_dict = {}
def set_value(key, value):
#定义一个全局变量
_global_dict[key] = value
def get_value(key):
#获得一个全局变量,不存在则提示读取对应变量失败
try:
return _global_dict[key]
except:
print('读取'+key+'失败\r\n')
其他文件需要用到的,则import global_var.py。然后在主文件初始化一下,global_var._init()
接着便可以随便使用了,比如先定义(定义字典的时候顺便写入初始值):
def task2_train():
global_var.set_value('flag_run_task', 1)
train_2.train()
def task2_test():
global_var.set_value('flag_run_task', 2)
test_2.test()
def task3_train():
global_var.set_value('flag_run_task', 3)
main_3.run()
使用的时候,直接get下字典对应键值,在循环中做如下实现:
另外,如果是多线程,可能会出现一个线程写入这个变量,另一个线程又在读取,从可靠性的角度考虑,多线程时读写最好加个锁同步一下
定义了一个函数一直不出图,最后发现是循环的问题,最后要加上:
root.mainloop()
grid是布局方法,也就是说我们每次设置一个控件都需要将其grid,否则将不显示
滚动文本框ScrolledText,其可以设置字体,颜色等参数
可变的文本,文本我们采取的也是放在label里的方式
var=StringVar()#设置变量
label=Label(root,font=('微软雅黑',10),fg='red',textvariable=var)
label.grid()
var.set('sth')
如果在程序执行中,需要对文本进行更改时,可以再次使用var.set
TKinter自身刷新GUI是单线程的,用户在调用mainloop方法后,主线程会一直不停循环刷新GUI,但是如果用户给某个widget绑定了一个很耗时的方法A时,这个方法A也是在主线程里调用,于是这个耗时的方法A会阻塞住刷新GUI的主线程,表现就是整个GUI卡住了,只有等这个耗时的方法结束后,GUI才会对用户操作响应
最简单的解决上述问题的办法就是利用多线程,把两个耗时方法丢到两个子线程里运行,就可以避开主线程被阻塞的问题
threading
可以实例化一个多线程对象,使用th.setDaemon(True)
守护线程,通过start
就可以开启。
说一下th.setDaemon(True)守护线程:
python中得thread的一些机制和C/C++不同:在C/C++中,主线程结束后,其子线程会默认被主线程kill掉。而在python中,主线程结束后,会默认等待子线程结束后,主线程才退出。
那么尴尬的问题就出现了,有一种情况,比如说在linux系统中存在脱离于终端的线程,即父进程在创建子进程之后先于子进程退出,会造成这个子进程变为“孤儿进程”
如果你忘记杀死子线程,那么好了,你杀主线程的时候其就会挂起等待直至子线程结束,所以为了避免这样的情况,python有两个函数管理线程:join
和setDaemon
join
:如在一个线程B中调用threada.join(),则threada结束后,线程B才会接着threada.join()往后运行。 setDaemon
:主线程A启动了子线程B,调用b.setDaemaon(True),则主线程结束时,会把子线程B也杀死,与C/C++中得默认效果是一样的。
一般情况下,在start前面加一下setDaemon(True)
def fun():
for i in range(1, 5+1):
th=threading.Thread(target=count,args=(i,))
th.setDaemon(True)#守护线程
th.start()
利用多线程,可以把两个耗时方法丢到两个子线程里运行,就可以避开主线程被阻塞的问题
def __A(self):
print("start to run proc A")
time.sleep(3)
print("proc A finished")
# 子线程构建
def A(self):
T = threading.Thread(target=self.__A)
T.start()
当有需要在text上显示的输出时,需要将标准输出stdout重定向到了一个自定义的类里,这个类的write方法可以更改Text的内容
经过重定向后,我们需要定义一个如下函数展示输出:
需要注意的是,我们尽量不应该把上面代码里的show方法丢到子线程里去跑。主要原因如下:
(1)上述代码里,利用子线程去更新Text是不安全的,因为可能存在不同线程同时修改Text的情况,这样可能导致打印出来的内容直接混乱掉。
(2)上述代码可能会直接报错,这个应该和TCL版本有关,在Google,Stackoverflow上基本都是不推荐子线程里更新GUI。
目前,比较好的解决GUI阻塞,而且不在子线程里更新GUI的办法,还是利用python自带的队列Queue,以及Tkinter下面的after方法。首先说下Queue这个class,Queue是python自带的一个队列class,其应用遵循着先入先出的原则。利用Queue.put方法将元素推进Queue里,再利用Queue.get方法将元素取出,最先推进去的元素会被最先取出。看下面的例子
import Queue
import time
queue = Queue.Queue()
for i in range(0, 4):
time.sleep(0.5)
element = "element %s"%i
print "put %s"%element
queue.put(element)
while not queue.empty():
time.sleep(0.5)
print "get %s"%queue.get()
# coding=utf-8
from Tkinter import *
from ttk import *
import threading
import time
import sys
import Queue
def fmtTime(timeStamp):
timeArray = time.localtime(timeStamp)
dateTime = time.strftime("%Y-%m-%d %H:%M:%S", timeArray)
return dateTime
#自定义re_Text,用于将stdout映射到Queue
class re_Text():
def __init__(self, queue):
self.queue = queue
def write(self, content):
self.queue.put(content)
class GUI():
def __init__(self, root):
#new 一个Quue用于保存输出内容
self.msg_queue = Queue.Queue()
self.initGUI(root)
#在show_msg方法里,从Queue取出元素,输出到Text
def show_msg(self):
while not self.msg_queue.empty():
content = self.msg_queue.get()
self.text.insert(INSERT, content)
self.text.see(END)
#after方法再次调用show_msg
self.root.after(100, self.show_msg)
def initGUI(self, root):
self.root = root
self.root.title("test")
self.root.geometry("400x200+700+500")
self.root.resizable = False
self.button = Button(self.root, text="click", width=10, command=self.show)
self.button.pack(side="top")
self.scrollBar = Scrollbar(self.root)
self.scrollBar.pack(side="right", fill="y")
self.text = Text(self.root, height=10, width=45, yscrollcommand=self.scrollBar.set)
self.text.pack(side="top", fill=BOTH, padx=10, pady=10)
self.scrollBar.config(command=self.text.yview)
#启动after方法
self.root.after(100, self.show_msg)
#将stdout映射到re_Text
sys.stdout = re_Text(self.msg_queue)
root.mainloop()
def __show(self):
i = 0
while i < 3:
print fmtTime(time.time())
time.sleep(1)
i += 1
def show(self):
T = threading.Thread(target=self.__show, args=())
T.start()
if __name__ == "__main__":
root = Tk()
myGUI = GUI(root)
打印线程
# coding:utf-8
from tkinter import *
# from tkinter.ScrolledText import ScrolledText # 文本滚动条
import threading
import time
from PIL import ImageTk, Image
def count(i):
for k in range(1, 100 + 1):
text.insert(END, '第' + str(i) + '线程count: ' + str(k) + '\n')
time.sleep(0.001)
def fun():
for i in range(1, 5 + 1):
th = threading.Thread(target=count, args=(i,))
th.setDaemon(True) # 守护线程
th.start()
var.set('MDZZ')
root = Tk()
throot.geometry('+600+100') # 窗口呈现位置
text = Text(root, font=('微软雅黑', 10), fg='blue')
text.grid()
button = Button(root, text='sth', font=('微软雅黑', 10), command=fun)
button.grid()
var = StringVar() # 设置变量
label = Label(root, font=('微软雅黑', 10), fg='red', textvariable=var)
label.grid()
var.set('sth')
root.mainloop()
按钮调用方法函数:
开启线程函数:
【Python】TKinter在多线程时刷新GUI的一些碎碎念
https://blog.csdn.net/sm9sun/article/details/53743116
注意python单变量是不共享内存的,可以连等复制,数组类型就不可
In [1]: a = b = c = []
In [2]: a.append(1)
In [3]: a
Out[3]: [1]
In [4]: b
Out[4]: [1]
In [5]: a = b = c =1
In [6]: a
Out[6]: 1
In [7]: a = 2
In [8]: b
Out[8]: 1
In [9]: a
Out[9]: 2
所以最保险的写法就是分开写
Python 语言提供 filter()
函数,语法如下:
filter(function, sequence)
filter()
函数的功能:对 sequence 中的 item 依次执行 function(item),将结果为 True 的 item 组成一个 List/String/Tuple(取决于 sequence 的类型)并返回。有了这个函数,上面的代码可以简化为:
divide_by_three = lambda x : True if x % 3
0 else False selected_numbers = filter(divide_by_three, range(1, 11))
将 lambda 表达式放在语句中,代码简化到只需要一句话就够了:
selected_numbers = filter(lambda x: x % 3 == 0, range(1, 11))
apply函数是pandas
里面所有函数中自由度最高的函数。该函数如下:
DataFrame.apply(func, axis=0, broadcast=False, raw=False, reduce=None, args=(), **kwds)
该函数最有用的是第一个参数,这个参数是函数,相当于
C/C++
的函数指针。这个函数需要自己实现,函数的传入参数根据
axis
来定,比如axis = 1
,就会把一行数据作为Series
的数据结构传入给自己实现的函数中,我们在函数中实现对Series
不同属性之间的计算,返回一个结果,则apply
函数会自动遍历每一行DataFrame
的数据,最后将所有结果组合成一个Series
数据结构并返回。
DataFrame.apply()
函数则会遍历每一个元素,对元素运行指定的 function。比如下面的示例:
import pandas as pd
import numpy as np
matrix = [
[1,2,3],
[4,5,6],
[7,8,9]
]
df = pd.DataFrame(matrix, columns=list('xyz'), index=list('abc'))
df.apply(np.square)
如果只想 apply()
作用于指定的行和列,可以用行或者列的 name
属性进行限定。比如下面的示例将 x 列进行平方运算:
x y z
a 1 2 3
b 16 5 6
c 49 8 9
下面的示例对 x 和 y 列进行平方运算:
x y z
a 1 4 3
b 16 25 6
c 49 64 9
下面的示例对第一行 (a 标签所在行)进行平方运算:
默认情况下 axis=0
表示按列,axis=1
表示按行。