内容
try: # 以绝对导入的方式导入cofig对象,并获取其{model_name}Config!
config = getattr(importlib.import_module('config'), f"{model_name}Config")
except AttributeError:
print(f"{model_name} not included!")
exit()
这里就是config下的属性类
- 下面是解析behavior.tsv文件, behavior.tsv文件如下;
这就是user-1的clicked News
共有五列: 分别是’impression_id’, ‘user’, ‘time’, ‘clicked_news’, ‘impressions’! 但是文件中没有给出列明的,需要自己来定义!
- 下面是解析后的behavior_parsed.tsv文件:
def parse_behaviors()
def parse_behaviors(source, target, user2int_path):
"""
Parse behaviors file in training set.
Args:
source: source behaviors file
target: target behaviors file
user2int_path: path for saving user2int file
"""
print(f"Parse {source}")
behaviors = pd.read_table(
source,
header=None,
names=['impression_id', 'user', 'time', 'clicked_news', 'impressions'])
behaviors.clicked_news.fillna(' ', inplace=True) #使用空格来填充缺失值,并修改原文件
behaviors.impressions = behaviors.impressions.str.split() #以空字符为分隔符来切分字符串,并返回list列表,没有指定num,所以是全部分割
user2int = {} #定义空字典,用于存储用户转为索引
for row in behaviors.itertuples(index=False): #将DataFrame转换为tuple并访问每行
if row.user not in user2int: #如果该用户没有在字典中
user2int[row.user] = len(user2int) + 1 #usr2int["U87243"] = 0 + 1,也就是给定索引,记得是从1开始的,不是从0!
#最普通的创建DataFrame方法,其中data = user2int.items(),是元组数组; index自动; columns = user 和 int
#将该DataFrame转换为csv文件, 分隔符是"\t",一个tab! 不保留原来的索引
pd.DataFrame(user2int.items(), columns=['user',
'int']).to_csv(user2int_path,
sep='\t',
index=False)
print( #处理完数据了,看看有多少有效的user_int
f'Please modify `num_users` in `src/config.py` into 1 + {len(user2int)}'
)
#获取了df矩阵中底index行,第'user'列! 也就是将用户名改成index
for row in behaviors.itertuples():
behaviors.at[row.Index, 'user'] = user2int[row.user]
#进度条展示! 名字是Balancing data,遍历的是整个文件
for row in tqdm(behaviors.itertuples(), desc="Balancing data"):
#上面可以查看behaviors中的impression属性是什么!
#我们遍历每个用户的impression,然后选择尾号为1和0的分别将其封印为list后再变成可迭代的!
#其中错误的样本需要进行shuffle,洗牌,再装成可迭代对象
positive = iter([x for x in row.impressions if x.endswith('1')])
negative = [x for x in row.impressions if x.endswith('0')]
random.shuffle(negative)
negative = iter(negative)
pairs = []
try:
while True: #这就是一个用户要他所有正样本加上两个负样本!
pair = [next(positive)]
#negative_sampling_ratio = 2 # K
for _ in range(config.negative_sampling_ratio):
pair.append(next(negative))
pairs.append(pair)
except StopIteration:
pass
behaviors.at[row.Index, 'impressions'] = pairs #取完后,再换回原behaviors
# 数据消除空白值,并且重新索引!
behaviors = behaviors.explode('impressions').dropna(
subset=["impressions"]).reset_index(drop=True)
#创建新的列,列名为:'candidate_news', 'clicked'
#在pandas,map()会对behaviors.impressions的元素进行操作
behaviors[['candidate_news', 'clicked']] = pd.DataFrame(
behaviors.impressions.map(
lambda x: (' '.join([e.split('-')[0] for e in x]), ' '.join(
[e.split('-')[1] for e in x]))).tolist())
#将某些列转为csv文件
behaviors.to_csv(
target,
sep='\t',
index=False,
columns=['user', 'clicked_news', 'candidate_news', 'clicked'])
def parse_news()
new.tsv中的内容:
前4个列: ‘id’, ‘category’, ‘subcategory’, ‘title’,
后3列:‘abstract’, ‘title_entities’, ‘abstract_entities’
其中倒数后两列中的标签信息:
Label/ Type/ WikidataId/ Confidence/ OccurrenceOffsets/ SurfaceForms/
def parse_news(source, target, roberta_output_dir, category2int_path,
word2int_path, entity2int_path, mode):
#这个直接就是英文了, 就是说模式不同,这几个参数的意义也就不同了!
#如果是训练模式,那么这个路径就是要保存的解析的 如果是测试模式,那么就是需要加载了
"""
Parse news for training set and test set
Args:
source: source news file
target: target news file
if mode == 'train':
category2int_path, word2int_path, entity2int_path: Path to save
elif mode == 'test':
category2int_path, word2int_path, entity2int_path: Path to load from
"""
print(f"Parse {source}")
news = pd.read_table(source, #读入源文件
header=None,
usecols=[0, 1, 2, 3, 4, 6, 7],
quoting=csv.QUOTE_NONE,
names=[
'id', 'category', 'subcategory', 'title',
'abstract', 'title_entities', 'abstract_entities'
]) # TODO try to avoid csv.QUOTE_NONE
news.title_entities.fillna('[]', inplace=True) #处理空值,并用[]来覆盖
news.abstract_entities.fillna('[]', inplace=True)
news.fillna(' ', inplace=True)
tokenizer = RobertaTokenizer.from_pretrained("roberta-base") #需要读入预训练模型
title_roberta = tokenizer(news.title.tolist(), #将一个句子进行简单的切分!
padding='max_length',
truncation=True, #超出padding部分截断
max_length=config.num_words_title)
abstract_roberta = tokenizer(news.abstract.tolist(), #同上! 也是这样的定义方式
padding='max_length',
truncation=True,
max_length=config.num_words_abstract)
roberta_df = pd.DataFrame(data=[ # words的ids
title_roberta['input_ids'], title_roberta['attention_mask'],
abstract_roberta['input_ids'], abstract_roberta['attention_mask']
]).T
roberta_df.columns = [ #重定义列名
'title_roberta', 'title_mask_roberta', 'abstract_roberta',
'abstract_mask_roberta'
]
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
for x in [title_roberta, abstract_roberta]: #经过Tokenizer后是一个字典,存放着分割后的words的id以及mask的id
for key in x.keys(): #我们访问该字典的两个属性
x[key] = torch.tensor(x[key]).to(device) #将该属性下的id放入到GPU上
#根据给出的路径来创建目录
Path(roberta_output_dir).mkdir(parents=True, exist_ok=True)
# roberta = RobertaModel.from_pretrained('roberta-base',
# return_dict=True).to(device)
#嵌入RobertModel! 前面的Tokenizer是预处理! 进行分词
if torch.cuda.device_count() > 1:
roberta = RobertaModel.from_pretrained('roberta-base',return_dict=True)
roberta = torch.nn.DataParallel(roberta)
print(next(roberta.parameters()).device) # 输出:cpu或者是cuda
roberta.to(device)
print(next(roberta.parameters()).device) # 输出:cpu或者是cuda
with torch.no_grad(): #不需要梯度更新
title_last_hidden_state = []
title_pooler_output = []
abstract_last_hidden_state = []
abstract_pooler_output = []
for count in tqdm(range(math.ceil(len(news) / config.batch_size)), #将news分批次
desc="Calculating news embeddings with RoBERTa"):
title_roberta_minibatch = {
k: v[count * config.batch_size:(1 + count) * config.batch_size]
for k, v in title_roberta.items()
}
# 这里的意思就是: 我们遍历访问title_roberta一部分,也就是第count个batch_size,它的索引是(count * config.batch_size:(1 + count) * config.batch_size)并放到minibatch字典!
# 后面有关于dict.items()的介绍!
title_outputs = roberta(**title_roberta_minibatch)# **代表的是提取字典中的键对儿值,也就是一对! 并处理
title_last_hidden_state.append( #将输出结果放到预先定义的列表中,后面的同理
title_outputs['last_hidden_state'].cpu().numpy())
title_pooler_output.append(
title_outputs['pooler_output'].cpu().numpy())
abstract_roberta_minibatch = {
k: v[count * config.batch_size:(1 + count) * config.batch_size]
for k, v in abstract_roberta.items()
}
abstract_outputs = roberta(**abstract_roberta_minibatch)
abstract_last_hidden_state.append(
abstract_outputs['last_hidden_state'].cpu().numpy())
abstract_pooler_output.append(
abstract_outputs['pooler_output'].cpu().numpy())
#将处理后的结果保存到文件中
np.save(path.join(roberta_output_dir, 'title_last_hidden_state.npy'),
np.concatenate(title_last_hidden_state, axis=0))
np.save(path.join(roberta_output_dir, 'title_pooler_output.npy'),
np.concatenate(title_pooler_output, axis=0))
np.save(
path.join(roberta_output_dir, 'abstract_last_hidden_state.npy'),
np.concatenate(abstract_last_hidden_state, axis=0))
np.save(path.join(roberta_output_dir, 'abstract_pooler_output.npy'),
np.concatenate(abstract_pooler_output, axis=0))
def parse_row(row):
entity_confidence_threshold = 0.5
news.tsv中后两列: ‘title_entities’, ‘abstract_entities’
**这个单元格: [ {}, {} ]**是一个list!
news.tsv第二列: category
def parse_row(row): #category转为int!
#new_row = [row.id, category2int[?],
#category2int[!], num_words_title个0组成的list, 同上, 同上, 同上]
new_row = [
row.id,
category2int[row.category] if row.category in category2int else 0,
category2int[row.subcategory] if row.subcategory in category2int else 0,
[0] * config.num_words_title, [0] * config.num_words_abstract,
[0] * config.num_words_title, [0] * config.num_words_abstract
]
# Calculate local entity map (map lower single word to entity)
local_entity_map = {}
for e in json.loads(row.title_entities): #遍历访问list元素, 每一个元素就是一个字典
#查看该news的属性,是不是置信度够高! 维基数据ID是不是在实体中
if e['Confidence'] > config.entity_confidence_threshold and e[
'WikidataId'] in entity2int:
#' '.join()用空格来分割字符
#lower().split():将分割后的字符改为小写后再默认以空格符来分割成多个字符串
for x in ' '.join(e['SurfaceForms']).lower().split():
local_entity_map[x] = entity2int[e['WikidataId']] #将实体每个字符都设置为实体的标签
for e in json.loads(row.abstract_entities): #同上
if e['Confidence'] > config.entity_confidence_threshold and e[
'WikidataId'] in entity2int:
for x in ' '.join(e['SurfaceForms']).lower().split():
local_entity_map[x] = entity2int[e['WikidataId']]
try:
for i, w in enumerate(word_tokenize(row.title.lower())): #将标题切tokens
if w in word2int: #如果该单词在word2int中,那么就记住该单词的int值放到num[3][i]列表中
new_row[3][i] = word2int[w]
if w in local_entity_map: #如果该单词在局部实体图中
new_row[5][i] = local_entity_map[w]
except IndexError:
pass
try:
for i, w in enumerate(word_tokenize(row.abstract.lower())): #将摘要切tokens
if w in word2int:
new_row[4][i] = word2int[w]
if w in local_entity_map:
new_row[6][i] = local_entity_map[w]
except IndexError:
pass
return pd.Series(new_row, #放入到dataFrame,并返回
index=[
'id', 'category', 'subcategory', 'title',
'abstract', 'title_entities', 'abstract_entities'
])
后面同样是def parse_news()函数中
if mode == 'train':
category2int = {} #类别转化为int
word2int = {} #单词转为int
word2freq = {} #单词转为频度
entity2int = {} #实体转为int
entity2freq = {} #实体转为频度
for row in news.itertuples(index=False): # 遍历新闻的每个元组
if row.category not in category2int: # 如果该行的类别不在category2int
category2int[row.category] = len(category2int) + 1
if row.subcategory not in category2int: # 如果子类别不在category2int中
category2int[row.subcategory] = len(category2int) + 1
for w in word_tokenize(row.title.lower()): #row.title.lower()
if w not in word2freq: #如果w不在word2freq,就是1; 否则后面加1
word2freq[w] = 1
else:
word2freq[w] += 1
for w in word_tokenize(row.abstract.lower()):
if w not in word2freq: #后面都是这样的
word2freq[w] = 1
else:
word2freq[w] += 1
for e in json.loads(row.title_entities): #times就是等于len([12])*0.99
times = len(e['OccurrenceOffsets']) * e['Confidence']
if times > 0:
if e['WikidataId'] not in entity2freq: # 实体转为频度
entity2freq[e['WikidataId']] = times
else:
entity2freq[e['WikidataId']] += times
for e in json.loads(row.abstract_entities): #摘要
times = len(e['OccurrenceOffsets']) * e['Confidence']
if times > 0:
if e['WikidataId'] not in entity2freq:
entity2freq[e['WikidataId']] = times
else:
entity2freq[e['WikidataId']] += times
for k, v in word2freq.items(): #遍历word2freq的key值和values值
if v >= config.word_freq_threshold:
word2int[k] = len(word2int) + 1
for k, v in entity2freq.items():
if v >= config.entity_freq_threshold:
entity2int[k] = len(entity2int) + 1
parsed_news = news.swifter.apply(parse_row, axis=1) #将parse_row()函数用在news的行
parsed_news = pd.concat([parsed_news, roberta_df], axis=1) #将两者按照行来concat(也就是从下边)
parsed_news.to_csv(target, sep='\t', index=False) #存储到target到csv文件
pd.DataFrame(category2int.items(), #将category2int存储
columns=['category', 'int']).to_csv(category2int_path,
sep='\t',
index=False)
print(
f'Please modify `num_categories` in `src/config.py` into 1 + {len(category2int)}'
)
pd.DataFrame(word2int.items(), columns=['word',
'int']).to_csv(word2int_path,
sep='\t',
index=False)
print(
f'Please modify `num_words` in `src/config.py` into 1 + {len(word2int)}'
)
pd.DataFrame(entity2int.items(),
columns=['entity', 'int']).to_csv(entity2int_path,
sep='\t',
index=False)
print(
f'Please modify `num_entities` in `src/config.py` into 1 + {len(entity2int)}'
)
elif mode == 'test': #如果是test模式,
category2int = dict(pd.read_table(category2int_path).values.tolist())
# na_filter=False is needed since nan is also a valid word
word2int = dict(
pd.read_table(word2int_path, na_filter=False).values.tolist())
#需要将值转为list
entity2int = dict(pd.read_table(entity2int_path).values.tolist())
parsed_news = news.swifter.apply(parse_row, axis=1) #parse_new同样应用到news上
parsed_news = pd.concat([parsed_news, roberta_df], axis=1)
parsed_news.to_csv(target, sep='\t', index=False)
else:
print('Wrong mode!')
def generate_word_embedding(source, target, word2int_path)
def generate_word_embedding(source, target, word2int_path):
"""
Generate from pretrained word embedding file
If a word not in embedding file, initial its embedding by N(0, 1) #创建Embedding
Args:
source: path of pretrained word embedding file, e.g. glove.840B.300d.txt
target: path for saving word embedding. Will be saved in numpy format
word2int_path: vocabulary file when words in it will be searched in pretrained embedding file
"""
# na_filter=False is needed since nan is also a valid word
# word, int
word2int = pd.read_table(word2int_path, na_filter=False, index_col='word')
source_embedding = pd.read_table(source, #单词嵌入式表示
index_col=0,
sep=' ',
header=None,
quoting=csv.QUOTE_NONE,
names=range(config.word_embedding_dim))
# word, vector
source_embedding.index.rename('word', inplace=True) #原单词嵌入的索引重命名为word
# word, int, vector
merged = word2int.merge(source_embedding, #单词的合并,采用交集方式; 左index和右index都是True
how='inner',
left_index=True,
right_index=True)
merged.set_index('int', inplace=True) #重新设置index,并且不保留原来的
missed_index = np.setdiff1d(np.arange(len(word2int) + 1), #在atr1中而不在atr2中(也就是缺失的数组)
merged.index.values)
missed_embedding = pd.DataFrame(data=np.random.normal(
size=(len(missed_index), config.word_embedding_dim)))
missed_embedding['int'] = missed_index
missed_embedding.set_index('int', inplace=True)
final_embedding = pd.concat([merged, missed_embedding]).sort_index()
np.save(target, final_embedding.values)
print(
f'Rate of word missed in pretrained embedding: {(len(missed_index)-1)/len(word2int):.4f}'
)
def transform_entity_embedding(source, target, entity2int_path):
def transform_entity_embedding(source, target, entity2int_path):
#将实体的embedding转化为numpy格式
"""
Args:
source: path of embedding file
target: path of transformed embedding file in numpy format
entity2int_path
"""
entity_embedding = pd.read_table(source, header=None) #读入soure,没有列名!
entity_embedding['vector'] = entity_embedding.iloc[:,
1:101].values.tolist()
#将列名从0变为entity
entity_embedding = entity_embedding[[0, 'vector']].rename(columns={0: "entity"})
entity2int = pd.read_table(entity2int_path)
merged_df = pd.merge(entity_embedding, entity2int,
on='entity').sort_values('int')
#这里是将某个词的向量变为随机值! 可以看到np.random.normal(size = (n个, d维度))
entity_embedding_transformed = np.random.normal(
size=(len(entity2int) + 1, config.entity_embedding_dim))
for row in merged_df.itertuples(index=False): #将某些列设置为正常值
entity_embedding_transformed[row.int] = row.vector
np.save(target, entity_embedding_transformed) #这样就形成了转换后的实体
main()函数
def parse_behaviors(source, target, user2int_path):
"""
Parse behaviors file in training set.
Args:
source: source behaviors file
target: target behaviors file
user2int_path: path for saving user2int file
"""
def parse_news(source, target, roberta_output_dir, category2int_path,
word2int_path, entity2int_path, mode):
"""
Parse news for training set and test set
Args:
source: source news file
target: target news file
if mode == 'train':
category2int_path, word2int_path, entity2int_path: Path to save
elif mode == 'test':
category2int_path, word2int_path, entity2int_path: Path to load from
"""
def generate_word_embedding(source, target, word2int_path):
"""
Generate from pretrained word embedding file
If a word not in embedding file, initial its embedding by N(0, 1) #创建Embedding
Args:
source: path of pretrained word embedding file, e.g. glove.840B.300d.txt
target: path for saving word embedding. Will be saved in numpy format
word2int_path: vocabulary file when words in it will be searched in pretrained embedding file
"""
def transform_entity_embedding(source, target, entity2int_path):
#将实体的embedding转化为numpy格式
"""
Args:
source: path of embedding file
target: path of transformed embedding file in numpy format
entity2int_path
"""
if __name__ == '__main__':
train_dir = './data/train'
val_dir = './data/val'
test_dir = './data/test'
# 下面都是相同的,都是处理原数据,之后再使用glove来进行
print('Process data for training')
# 第一步: training (只是使用glove词典)
# 先处理好用户行为、以及news的数字化处理! 同时形成用于glove和roberta的数据格式
print('Parse behaviors')
parse_behaviors(path.join(train_dir, 'behaviors.tsv'),
path.join(train_dir, 'behaviors_parsed.tsv'),
path.join(train_dir, 'user2int.tsv')) #
print('Parse news')
parse_news(path.join(train_dir, 'news.tsv'),
path.join(train_dir, 'news_parsed.tsv'),
path.join(train_dir, 'roberta'),
path.join(train_dir, 'category2int.tsv'),
path.join(train_dir, 'word2int.tsv'),
path.join(train_dir, 'entity2int.tsv'),
mode='train')
# 形成我们的单词向量嵌入
print('Generate word embedding')
generate_word_embedding(
f'./data/glove/glove.840B.{config.word_embedding_dim}d.txt',
path.join(train_dir, 'pretrained_word_embedding.npy'),
path.join(train_dir, 'word2int.tsv'))
# 形成实体嵌入
print('Transform entity embeddings')
transform_entity_embedding(
path.join(train_dir, 'entity_embedding.vec'),
path.join(train_dir, 'pretrained_entity_embedding.npy'),
path.join(train_dir, 'entity2int.tsv'))
# 第二步: 验证(使用我们的roberta)因为后面是需要进行微调roberta的!
print('\nProcess data for validation')
print('Parse news')
parse_news(path.join(val_dir, 'news.tsv'),
path.join(val_dir, 'news_parsed.tsv'),
path.join(val_dir, 'roberta'),
path.join(train_dir, 'category2int.tsv'),
path.join(train_dir, 'word2int.tsv'),
path.join(train_dir, 'entity2int.tsv'),
mode='test')
#第三步:测试(同样使用我们的roberta)
print('\nProcess data for test')
print('Parse news')
parse_news(path.join(test_dir, 'news.tsv'),
path.join(test_dir, 'news_parsed.tsv'),
path.join(test_dir, 'roberta'),
path.join(train_dir, 'category2int.tsv'),
path.join(train_dir, 'word2int.tsv'),
path.join(train_dir, 'entity2int.tsv'),
mode='test')
补充:
1. getattr()函数
-
描述
getattr() 函数用于返回一个对象的属性值。 -
语法
getattr(object, name[, default]) -
参数
object – 对象。
name – 字符串,对象属性。
default – 默认返回值,如果不提供该参数,在没有对应属性时,将触发 AttributeError -
返回值
返回对象属性值 -
实例
>>>class A(object):
... bar = 1
...
>>> a = A()
>>> getattr(a, 'bar') # 获取属性 bar 值
1
>>> getattr(a, 'bar2') # 属性 bar2 不存在,触发异常
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'bar2'
>>> getattr(a, 'bar2', 3) # 属性 bar2 不存在,但设置了默认值
3
>>>
实例2:
>>> class A(object):
... def set(self, a, b):
... x = a
... a = b
... b = x
... print a, b
...
>>> a = A()
>>> c = getattr(a, 'set')
>>> c(a='1', b='2')
2 1
>>>
实际的实例:
try:
config = getattr(importlib.import_module('config'), f"{model_name}Config")
except AttributeError:
print(f"{model_name} not included!")
exit()
2. importlib.import_module()
这样做的目的就是为了动态的引入模块!
import importlib
params = importlib.import_module('b.c.c') #绝对导入 在同一文件夹下则不同b了
params_ = importlib.import_module('.c.c',package='b') #相对导入
3. f-strings 字符串格式化
这种在字符串前面加“f”就相当于 “XX{ }”.format(model_name)
举例:
name = '宝元'
age = 18
sex = '男'
msg1 = F'姓名:{name},性别:{age},年龄:{sex}' # 大写字母也可以
msg = f'姓名:{name},性别:{age},年龄:{sex}' # 建议小写
print(msg)
4. pd.read_table()
原代码中是header和names混合使用! 如果header = None; names就该设置列明
quoting=3或是quoting=csv.QUOTE_NONE”
5. fillna()函数
具体请参考博文
我只摘录和原代码相关的内容!
该函数用来填充缺失值! 也就是NaN!
- inplace: 方法有改变原文件也有不改变原文件两种方式! 不改变原文件顾名思义也就是创建临时对象,只有在运行程序时有一个对象,相反,则是把原文件改了! 该
- 填充值
#二、指定inplace参数
print (df1.fillna(0,inplace=True))
print ("-------------------------")
print (df1)
使用0来填充,那么源代码就是使用" " 空格来填充
6. split()方法
-
描述:
str.split() 通过指定分隔符对字符串进行切片,如果参数 num 有指定值,则分隔 num+1 个子字符串 -
语法:
split() 方法语法:
str.split(str="", num=string.count(str)).
-
参数:
str – 分隔符,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等。
num – 分割次数。默认为 -1, 即分隔所有。(从第一个分隔符开始切分) -
返回值
返回分割后的字符串列表。(list列表) -
实例
>>>str = "Line1-abcdef \nLine2-abc \nLine4-abcd";
>>>print str.split( ); # 以空格为分隔符,包含 \n,如果为空的话,那么就是所有空字符
>>>print str.split(' ', 1 ); # 以空格为分隔符,分隔成两个
['Line1-abcdef', 'Line2-abc', 'Line4-abcd']
['Line1-abcdef', '\nLine2-abc \nLine4-abcd']
- 实例2
以下实例以 # 号为分隔符,指定第二个参数为 1,返回两个参数列表。
#!/usr/bin/python
# -*- coding: UTF-8 -*-
txt = "Google#Runoob#Taobao#Facebook"
# 第二个参数为 1,返回两个参数列表
x = txt.split("#", 1)
print x
7. iteritems()、 iterrows()、itertuples():
itertuples()
原博客
这是将原DataFrame转成一行一行的tuple,也就是小DataFrame!
如果我们想访问要和getattr结合!
举例:
假如原test是这样的!
当我们运行itertuples()时:
其它的请看链接,我暂时不需要
8. pd.DataFrame()
也就是创建DataFrame()
DataFrame是由多种类型的列构成的二维标签数据结构.[1]
往往包含index(行标签)和columns(列标签), 彼此独立, 互不影响
直观理解:DataFrame 是带标签的二维数组
所以问题在于如何创建DataFrame:
最普通的创建DataFrame
DataFrame()函数的参数index的值相当于行索引,若不手动赋值,将默认从0开始分配。columns的值相当于列索引,若不手动赋值,也将默认从0开始分配。
data = {
'性别':['男','女','女','男','男'],
'姓名':['小明','小红','小芳','大黑','张三'],
'年龄':[20,21,25,24,29]}
df = pd.DataFrame(data, index=['one','two','three','four','five'],
columns=['姓名','性别','年龄','职业'])
df
df.values 返回ndarray类型的对象
ndarray类型即numpy的 N 维数组对象,通常将DataFrame类型的数据转换为ndarray类型的比较方便操作。如对DataFrame类型进行切片操作需要df.iloc[ : , 1:3]这种形式,对数组类型直接X[ : , 1:3]即可。
X = df.values
print(type(X)) #显示数据类型
X
运行结果:
<class 'numpy.ndarray'>
[['小明' '男' 20 nan]
['小红' '女' 21 nan]
['小芳' '女' 25 nan]
['大黑' '男' 24 nan]
['张三' '男' 29 nan]]
df.iloc[ 行序,列序 ] 按序值返回元素
df.iloc[1,1]
Index(['one', 'two', 'three', 'four', 'five'], dtype='object')
df.at[index, columns]
作用:获取某个位置的值,例如获取第0行,第a列的值,即:index=0, columns = ‘a’
data = df.at[0, ‘a’]
9. items()
描述
Python 字典(Dictionary) items() 函数以列表返回可遍历的(键, 值) 元组数组。
语法
dict.items()
参数
无
返回值
返回可遍历的(键, 值) 元组数组 (不是list,而是数组)
实例
#!/usr/bin/python
# coding=utf-8
dict = {'Google': 'www.google.com', 'Runoob': 'www.runoob.com', 'taobao': 'www.taobao.com'}
print "字典值 : %s" % dict.items()
# 遍历字典列表
for key,values in dict.items():
print key,values
字典值 : [('Google', 'www.google.com'), ('taobao', 'www.taobao.com'), ('Runoob', 'www.runoob.com')]
Google www.google.com
taobao www.taobao.com
Runoob www.runoob.com
10. .to_csv()
1.首先查询当前的工作路径:
import os
os.getcwd() #获取当前工作路径
2.to_csv()是DataFrame类的方法,read_csv()是pandas的方法
dt.to_csv() #默认dt是DataFrame的一个实例,参数解释如下
- 路径 path_or_buf: A string path to the file to write or a StringIO
dt.to_csv('Result.csv') #相对位置,保存在getwcd()获得的路径下
dt.to_csv('C:/Users/think/Desktop/Result.csv') #绝对位置
- 分隔符 sep : Field delimiter for the output file (default ”,”)
dt.to_csv('C:/Users/think/Desktop/Result.csv',sep='?')#使用?分隔需要保存的数据,如果不写,默认是,
- 替换空值 na_rep: A string representation of a missing value (default ‘’)
dt.to_csv('C:/Users/think/Desktop/Result1.csv',na_rep='NA') #确实值保存为NA,如果不写,默认是空
- 是否保留行索引 index: whether to write row (index) names (default True)
dt.to_csv('C:/Users/think/Desktop/Result1.csv',index=0) #不保存行索引
- 是否保留列名 header: Whether to write out the column names (default True)
dt.to_csv('C:/Users/think/Desktop/Result.csv',header=0) #不保存列名
- 是否保留某列数据 cols: Columns to write (default None
dt.to_csv('C:/Users/think/Desktop/Result.csv',columns=['name']) #保存索引列和name列
11. tpdm(iterator)
Tqdm 是一个快速,可扩展的Python进度条,可以在 Python 长循环中添加一个进度提示信息,用户只需要封装任意的迭代器 tqdm(iterator)。
使用pip就可以安装。
- 参数:
iterable=None, 当然是我们要被迭代的对象! 迭代多少次,则显示多少
desc=None, 传入str类型,作为进度条标题(类似于说明)
total=None, 预期的迭代次数
leave=True,
file=None,
ncols=None, 可以自定义进度条的总长度
mininterval=0.1, 最小的更新间隔
maxinterval=10.0, 最大更新间隔
miniters=None,
ascii=None,
unit='it',
unit_scale=False,
dynamic_ncols=False,
smoothing=0.3,
bar_format=None,
initial=0,
position=None,
postfix 以字典形式传入 详细信息 例如 速度= 10,
- 操作1:
from tqdm import tqdm
for i in tqdm(range(10000)):
"""一些操作"""
pass
操作2:
dict = {"a":123,"b":456}
for i in tqdm(range(10),total=10,desc = "WSX",ncols = 100,postfix = dict,mininterval = 0.3):
pass
操作3
from tqdm import trange
from random import random, randint
from time import sleep
with trange(100) as t:
for i in t:
# Description will be displayed on the left
t.set_description('下载速度 %i' % i)
# Postfix will be displayed on the right,
# formatted automatically based on argument's datatype
t.set_postfix(loss=random(), gen=randint(1,999), str='详细信息',
lst=[1, 2])
sleep(0.1)
其中trange(i) 是 tqdm(range(i)) 的简单写法
13. x.endwith()
Python endswith() 方法用于判断字符串是否以指定后缀结尾,如果以指定后缀结尾返回True,否则返回False。可选参数"start"与"end"为检索字符串的开始与结束位置。
endswith()方法语法:
str.endswith(suffix[, start[, end]])
14. iter(object)
用于生成迭代对象,之后采用next()来访问它的每一个内容!
意义和for循环是一样的! 只不是可能是为了方便统一访问吧!
15. DataFrame.explode(self, column: Union[str, Tuple])
将类似列表的每个元素转换为一行,从而复制索引值。
- 参数
column : str或tuple
-返回值
DataFrame
将列表分解为子列的行;将为这些行复制索引。
-
Raises:
ValueError:
如果框架的列不是唯一的。 -
举例
>>> df = pd.DataFrame({'A': [[1, 2, 3], 'foo', [], [3, 4]], 'B': 1})
>>> df
A B
0 [1, 2, 3] 1
1 foo 1
2 [] 1
3 [3, 4] 1
>>> df.explode('A')
A B
0 1 1
0 2 1
0 3 1
1 foo 1
2 NaN 1
3 3 1
3 4 1
可以看到list中每个元素单独成为了一行! 行名和列名都保留
16. pandas之dropna()
该函数主要用于滤除缺失数据。
如果是Series,则返回一个仅含非空数据和索引值的Series,默认丢弃含有缺失值的行。
xx.dropna()
对于DataFrame:
data.dropna(how = 'all') # 传入这个参数后将只丢弃全为缺失值的那些行
data.dropna(axis = 1) # 丢弃有缺失值的列(一般不会这么做,这样会删掉一个特征)
data.dropna(axis=1,how="all") # 丢弃全为缺失值的那些列
data.dropna(axis=0,subset = ["Age", "Sex"]) # 丢弃‘Age’和‘Sex’这两列中有缺失值的行
17. pandas中的reset_index()
数据清洗时,会将带空值的行删除,此时DataFrame或Series类型的数据不再是连续的索引,可以使用reset_index()重置索引。
只有一个参数drop = True! 默认是False!
drop = False: 会保留原来不连续的索引成为新的一列!
drop = True: 会删除原来的索引
18. df[[‘name’]] 和 df[‘name’]
df.groupby(['key1','key2'])[['data2']].mean()
Out[27]:
data2
key1 key2
a one 0.072958
two -0.962946
b one 0.946299
two 1.576233
若对需要聚合的单列使用单中括号,则输出时不会带有列标签,末尾会单独输出一行属性列
df.groupby(['key1','key2'])['data2'].mean()
Out[29]:
key1 key2
a one 0.072958
two -0.962946
b one 0.946299
two 1.576233
Name: data2, dtype: float64
若需要将多列进行聚合时,单中括号和双中括号没有区别
df.groupby(['key1','key2'])['data1','data2'].mean()
Out[31]:
data1 data2
key1 key2
a one 0.018737 0.072958
two -1.319022 -0.962946
b one 0.917741 0.946299
two -1.288477 1.576233
df.groupby(['key1','key2'])[['data1','data2']].mean()
Out[30]:
data1 data2
key1 key2
a one 0.018737 0.072958
two -1.319022 -0.962946
b one 0.917741 0.946299
two -1.288477 1.576233
19. pandas中的map()
通过df.(tab)键,发现df的属性列表中有apply() 和 applymap(),但没有map().
map()是python 自带的方法, 可以对df某列内的元素进行操作
20. Roberta
Roberta是基于Bert的这是毋庸置疑的! 它的API
它的论文地址
它建立在BERT的基础上,修改了关键的超参数,去掉了next-sentence预训练目标,并使用更大的小批量和学习率进行训练。
论文摘要如下:
语言模型前训练已经带来了显著的成绩提高,但仔细比较不同的方法是具有挑战性的。训练在计算上很昂贵,通常是在不同大小的私有数据集上进行的,而且,正如我们将展示的,超参数选择对最终结果有重大影响。我们提出了一项BERT训练前复制研究(Devlin et al., 2019),仔细衡量了许多关键超参数和训练数据大小的影响。我们发现BERT明显缺乏训练,并且可以匹配或超过在它之后发布的每个模型的性能。我们最好的模型在GLUE, RACE和SQuAD上实现了最先进的结果。这些结果突出了以前被忽视的设计选择的重要性,并提出了关于最近报道的改进的来源的问题。我们发布我们的模型和代码。
Robertmodel (robustly Bert Model)其实就是加强版的bertmodel
具体只有以下几点的改变
1:pretraining 得数据从普通bert模型的16g 变成了160g
2.去除掉了nsp,也就是不做next sentence prediction
3.使用的动态mask,普通bert用的是静态mask,
区别就是静态mask,对于一个句子,mask掉部分词,塞进模型,训练完后,就换下一 句,而动态mask会多重复几次,每次都mask掉不同的词
4.training的过程使用更长的句子
技巧:
- 该实现与
BertModel
相同,只是进行了微小的嵌入调整,并为Roberta预先训练的模型进行了设置。 - RoBERTa具有与BERT相同的体系结构,但使用字节级BPE作为标记器(与GPT-2相同),并使用不同的预训练方案。
- RoBERTa没有
token_type_ids
,您不需要指明哪个令牌属于哪个段。只需用分离token分离您的段。tokenizer.sep_token
(或< / s >
) CamemBERT
是 RoBERTa的外皮。使用示例请参见此页。
该模型由julien-c贡献。可以在这里找到原始代码。
后面两者先进行前者后进行后者
RobertaTokenizer
class transformers.RobertaTokenizer(vocab_file, merges_file, errors=‘replace’,
bos_token=’<
s
{s}
s>’, eos_token=’<
/
s
{/s}
/s>’, sep_token=’<
/
s
{/s}
/s>’, cls_token=’<
s
{s}
s>’, unk_token=’<
/
u
n
k
{/unk}
/unk>’, pad_token=’<
/
p
a
d
{/pad}
/pad>’, mask_token=’<
/
m
a
s
k
{/mask}
/mask>’, add_prefix_space=False, **kwargs)
使用字节级字节对编码构造一个RoBERTaTokenizer,该标记赋予器派生自GPT-2标记赋予器。
这个标记赋予器已经被训练成将空格视为标记的一部分(有点像句子片段),所以无论单词是否在句子的开头(没有空格),它都将被不同的编码:
from transformers import RobertaTokenizer
tokenizer = RobertaTokenizer.from_pretrained("roberta-base")
tokenizer("Hello world")['input_ids']
#[0, 31414, 232, 328, 2]
tokenizer(" Hello world")['input_ids']
#[0, 20920, 232, 2]
您可以通过在实例化这个标记赋予器或在某些文本上调用它时传递add_prefix_space=True来绕过该行为,但由于模型不是以这种方式预先训练的,它可能会导致性能下降。
注意:
当与is_split_into_words=True
一起使用时,这个标记赋予器将在每个单词前添加一个空格(甚至是第一个)。
这个标记器继承了PreTrainedTokenizer
,它包含了大部分的主要方法。用户应该参考这个超类以获得关于这些方法的更多信息。
RobertaConfig和RobertModel
class transformers.RobertaConfig(pad_token_id=1, bos_token_id=0, eos_token_id=2, **kwargs)[SOURCE]
这是用于存储RobertaModel或TFRobertaModel配置的配置类。它用于根据指定的参数实例化RoBERTa模型,定义模型体系结构。
配置对象继承自PretrainedConfig,可用于控制模型输出。更多信息请阅读PretrainedConfig的文档。
RobertaConfig类直接继承了BertConfig。它重用相同的默认值。请查看父类了解更多信息。
举例:
from transformers import RobertaConfig, RobertaModel
# Initializing a RoBERTa configuration
configuration = RobertaConfig()
# Initializing a model from the configuration
model = RobertaModel(configuration)
# Accessing the model configuration
configuration = model.config
参数:
- vocab_file(str) - 词汇表文件的路径。
- merges_file (str) -合并文件的路径。
- errors(str, optional, defaults to “replace”) -更多信息请参见bytes.decode。
- bos_token (str, optional, defaults to “<
s
{s}
s>”) -在预训练期间使用的序列标记的开始。可以使用序列分类器标记。
Note:
当使用特殊标记构建序列时,这不是用于序列开始的标记。使用的令牌是cls_token。 - eos_token(str, optional, defaults to “<{/s}>”)
序列标记的结束。 - sep_token (str, optional, defaults to “<{/s}>”)
分隔符,用于从多个序列构建序列,例如用于序列分类的两个序列,或用于文本和用于问答的一个问题。它也被用作由特殊标记构建的序列的最后一个标记。 - cls_token (str, optional, defaults to “<
s
{s}
s>”)
在进行序列分类时使用的分类器标记(对整个序列进行分类,而不是对每个标记进行分类)。当使用特殊标记构建时,它是序列的第一个标记。 - unk_token (str, optional, defaults to “<
u
n
k
{unk}
unk>”)
未知的令牌。不在词汇表中的令牌不能转换为ID,而是被设置为这个令牌。 - pad_token(str, optional, defaults to “<
p
a
d
{pad}
pad>”)
用于填充的令牌,例如对不同长度的序列进行批处理时。 - mask_token(str, optional, defaults to “”)
用于屏蔽值的令牌。这是在使用掩码语言建模训练此模型时使用的令牌。这就是模型将要尝试预测的标记。 - add_prefix_space(bool, optional, defaults to False)
是否向输入添加初始空间。这样就可以像对待其他单词一样对待引导词。(RoBERTa标记器通过前面的空格检测单词的开头)。
函数
build_inputs_with_special_tokens()
通过连接和添加特殊标记,从序列或序列对构建用于序列分类任务的模型输入。RoBERTa序列的格式如下:
create_token_type_ids_from_sequences()
从传递给序列对分类任务的两个序列创建掩码。RoBERTa不使用令牌类型id,因此返回一个零列表。
get_special_tokens_mask()
从没有添加特殊标记的标记列表中检索序列id。当使用标记器prepare_for_model方法添加特殊标记时,将调用此方法。
save_vocabulary()
只保留标记赋予者的词汇表(词汇表+添加的标记)。
此方法不会保存标记赋予器的配置和特殊标记映射。使用_save_pretrained()保存标记赋予器的整个状态。
21. Tokenizer 统一使用
https://blog.csdn.net/claroja/article/details/108365064
主要是使用tokenizer,首先会分割文本成单词(tokens),然后将这些单词转换为数字。
在 pretraining or fine-tuning一个model时,使用from_pretrained()来处理文本
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained('bert-base-cased')
encoded_input = tokenizer("Hello, I'm a single sentence!")
print(encoded_input) #输出的是字典!
{'input_ids': [101, 138, 18696, 155, 1942, 3190, 1144, 1572, 13745, 1104, 159, 9664, 2107, 102],
'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
返回的是一个字典!
tokenizer可以接收列表。
通过参数可以给句子设定:
1.长度不够的句子,添加pad(padding=True)
2.超出长度的句子,截取truncate(truncation=True)
3.返回tensor(return_tensors=‘pt’)
22. Path().mkdir(parents=True, exist_ok=True)
该Path是pathlib模块中的! 不是os中的!
在介绍Python安全创建目录之前,先举一个不安全创建目录的方式:
if not os.path.exists(directory):
os.makedirs(directory)
在例子里,先判断目录是否存在,然后创建目录。这种方式是不安全的,它会导致竞争条件。在os.path.exists()和os.makedirs()之间的时间可能会出现目录被创建。不推荐使用这种方式。
Python 3.5+:
在python 3.5+可以使用pathlib的mkdir:
import pathlib
pathlib.Path('/my/directory').mkdir(parents=True, exist_ok=True)
pathlib的mkdir接收两个参数:
parents:如果父目录不存在,是否创建父目录。
exist_ok:只有在目录不存在时创建目录,目录已存在时不会抛出异常
23. torch.no_grad()
禁用梯度计算的上下文管理器。
当您确定不会调用Tensor.backward()时,禁用梯度计算对推理很有用。 它将减少计算所需的内存消耗,否则requires_grad=True。
在这种模式下,每次计算的结果都有requires_grad=False,即使输入是requires_grad=True。
这个上下文管理器是线程本地的; 它不会影响其他线程的计算。
也可作为装饰器。 (确保用括号实例化。)
24. math.ceil()
math.ceil() 返回大于整数的最小整数值,如果number已经是整数了那么就是相同的数
代码:
# Python code to demonstrate the working of ceil()
# importing "math" for mathematical operations
import math
x = 33.7
# returning the ceil of 33.7
print ("The ceil of 33.7 is:", end ="")
print (math.ceil(x))
输出: The ceil of 33.7 is:34
代码2:
# Python code to demonstrate the working of ceil()
# importing "math" for mathematical operations
import math
# prints the ceil using ceil() method
print ("math.ceil(-13.1):", math.ceil(-13.1))
print ("math.ceil(101.96):", math.ceil(101.96))
math.ceil(-13.1): -13
math.ceil(101.96): 102
25. **dict()
d1 = {
‘name’: ‘jim’,
‘age’: 18
}
d2 = {**d1,
‘color’: ‘yellow’
}
print(d2)
26. Bert、RoBerta的输入输出
- last_hidden_state:shape是(batch_size, sequence_length, hidden_size),hidden_size=768,它是模型最后一层输出的隐藏状态
- pooler_output:shape是(batch_size, hidden_size),这是序列的第一个token(classification token)的最后一层的隐藏状态,它是由线性层和Tanh激活函数进一步处理的,这个输出不是对输入的语义内容的一个很好的总结,对于整个输入序列的隐藏状态序列的平均化或池化通常更好。
- hidden_states:这是输出的一个可选项,如果输出,需要指定config.output_hidden_states=True,它也是一个元组,它的第一个元素是embedding,其余元素是各层的输出,每个元素的形状是(batch_size, sequence_length, hidden_size)
- attentions:这也是输出的一个可选项,如果输出,需要指定config.output_attentions=True,它也是一个元组,它的元素是每一层的注意力权重,用于计算self-attention heads的加权平均值
27 ’ '.join(str)
描述
将序列中的元素以指定的字符连接生成一个新的字符串。
语法
语法: ‘sep’.join(seq)
参数说明:
sep:分隔符。可以为空
seq:要连接的元素序列、字符串、元组、字典
返回值
返回通过指定字符连接序列中元素后生成的新字符串。
>>> a="abcd"
>>> ",".join(a)
'a,b,c,d'
>>> "|".join(['a','b','c'])
'a|b|c'
>>> ",".join(('a','b','c'))
'a,b,c'
28. swifter()
目前我在网上找到的pandas加速包有两个:modin和swifter
modin 宣称"通过更改一行代码来加速你的pandas工作流",官方文档https://github.com/modin-project/modin
swifter 对apply函数加速,官方文档https://github.com/jmcarpenter2/swifter
29. merge()
本篇详细说明merge的应用,join 和concatenate的拼接方法的与之相似。
pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,
left_index=False, right_index=False, sort=True,
suffixes=('_x', '_y'), copy=True, indicator=False,
validate=None)
参数如下:
- left: 拼接的左侧DataFrame对象
- right: 拼接的右侧DataFrame对象
- on: 要加入的列或索引级别名称。 必须在左侧和右侧DataFrame对象中找到。 如果未传递且left_index和right_index为False,则DataFrame中的列的交集将被推断为连接键。
- left_on:左侧DataFrame中的列或索引级别用作键。 可以是列名,索引级名称,也可以是长度等于DataFrame长度的数组。
- right_on: 左侧DataFrame中的列或索引级别用作键。 可以是列名,索引级名称,也可以是长度等于DataFrame长度的数组。
- left_index: 如果为True,则使用左侧DataFrame中的索引(行标签)作为其连接键。 对于具有MultiIndex(分层)的DataFrame,级别数必须与右侧DataFrame中的连接键数相匹配。
- right_index: 与left_index功能相似。
- how: One of ‘left’, ‘right’, ‘outer’, ‘inner’. 默认inner。inner是取交集,outer取并集。比如left:[‘A’,‘B’,‘C’];right[’'A,‘C’,‘D’];inner取交集的话,left中出现的A会和right中出现的另一个A进行匹配拼接,如果没有是B,在right中没有匹配到,则会丢失。'outer’取并集,出现的A会进行一一匹配,没有同时出现的会将缺失的部分添加缺失值。
- sort: 按字典顺序通过连接键对结果DataFrame进行排序。 默认为True,设置为False将在很多情况下显着提高性能。
- suffixes: 用于重叠列的字符串后缀元组。 默认为(‘x’,’ y’)。
- copy: 始终从传递的DataFrame对象复制数据(默认为True),即使不需要重建索引也是如此。
- indicator:将一列添加到名为_merge的输出DataFrame,其中包含有关每行源的信息。 _merge是分类类型,并且对于其合并键仅出现在“左”DataFrame中的观察值,取得值为left_only,对于其合并键仅出现在“右”DataFrame中的观察值为right_only,并且如果在两者中都找到观察点的合并键,则为left_only。
30. setdiff1d
属于numpy!
一、函数解释
setdiff1d(ar1, ar2, assume_unique=False)
1.功能:找到2个数组中集合元素的差异。
2.返回值:在ar1中但不在ar2中的已排序的唯一值。
3.参数:
ar1:array_like 输入数组。
ar2:array_like 输入比较数组。
assume_unique:bool。如果为True,则假定输入数组是唯一的,即可以加快计算速度。 默认值为False。
二、具体示例
1.assume_unique = False的情况:
a = np.array([1,2,3])
b = np.array([4,5,6])
c = np.setdiff1d(a, b)
print(c)#[1 2 3]
a = np.array([1,2,3])
b = np.array([1,2,3])
c = np.setdiff1d(a, b)
print(c)#[]
a = np.array([1,2,3])
b = np.array([2,3,4])
c = np.setdiff1d(a, b)
print(c)#[1]
a = np.array([1,2,3,4])
b = np.array([3,4,5,6])
c = np.setdiff1d(a, b)
print(c)#[1 2]
a = np.array([1,2,3,2,4,1])
b = np.array([3,4,5,6])
c = np.setdiff1d(a, b)
print(c)#[1 2]
a = np.array([8,2,3,2,4,1])
b = np.array([7,4,5,6,3])
c = np.setdiff1d(a, b)
print(c)#[1 2 8]
可以从最后看出返回的值从小到大排序,并且唯一。(8在a的第1位,2在a中重复了2次)
2.assume_unique = True的情况:
a = np.array([3,2,1])
b = np.array([4,5,6])
c = np.setdiff1d(a, b,True)
print(c)#[3 2 1]
a = np.array([8,2,3,2,4,1])
b = np.array([7,4,5,6,3])
c = np.setdiff1d(a, b,True)
print(c)#[8 2 2 1]
a = np.array([8,2,3,4,2,4,1])
b = np.array([7,9,5,6,3])
c = np.setdiff1d(a, b,True)
print(c)#[8 2 4 2 4 1]
可以看出把在a中的但是不在b中的元素按a中的顺序排序,并且不合并重复的元素,即假定输入数组也是唯一的,因此相比于False确实提升了运算速度。
31. df.rename()
df.rename()用于更改行列的标签,即行列的索引。可以传入一个字典或者一个函数。在数据预处理中,比较常用。
官方文档:
DataFrame.rename(self, mapper=None, index=None, columns=None, axis=None, copy=True, inplace=False, level=None, errors=‘ignore’)
参数实例:
import pandas as pd
df = pd.DataFrame({'name':['zhao','qian','sun','wang'],'mark':[150,122,155,132],'gender':['female','female','male','male']})
df
name mark gender
0 zhao 150 female
1 qian 122 female
2 zhou 155 male
3 wang 132 male
- mapper:dict or function
映射关系,可以是字典,也可以是一个函数。
df.rename({0:111})
name mark gender
111 zhao 150 female #行索引从0变为111
1 qian 122 female
2 zhou 155 male
3 wang 132 male
df.rename(lambda x: x+11) #参数也可以是函数,索引都加了11
name mark gender
11 zhao 150 female
12 qian 122 female
13 zhou 155 male
14 wang 132 male
2 index、columns、axis
这3个参数作用类似,dataframe中有行和列两个方向,在改名时,需要指明改名的是行还是列(默认是行),使用df.rename(index = mapper)或者df.rename(columns=mapper)的形式,和
df.rename(mapper,axis=0 or 1)的效果是一样的
df.rename(lambda x: x+'11',axis=1)
name11 mark11 gender11 #列索引都加了11,name变为name11
0 zhao 150 female
1 qian 122 female
2 zhou 155 male
3 wang 132 male
df.rename(columns=lambda x: x+'11')#等价于上面,写法更简洁直观
name11 mark11 gender11
0 zhao 150 female
1 qian 122 female
2 zhou 155 male
3 wang 132 male
- copy:bool,default = True
默认为True,效果不清楚。。。文档就一句话,与会复制底层数据(also copy underlying data), 等一个课代表解答一下。 - inplace:bool,default False
将结果返回赋值给原变量,无需再次将结果赋值给新变量。即df.rename(inplace=True)之后,df的值发生改变(pandas中好多方法都有这个参数,此处就演示了)
32.Bert和Glove
https://blog.csdn.net/weixin_37735081/article/details/94361265
- 词向量模型
词向量模型包括:word2vec、glove、fastText、elmo、GPT和bert、xlnet等。
这里面有些是“一揽子”表示的词向量模型,如word2vec、glove,是用一个固定的向量来表示一个具体的token(单词)。这样的好处是简单且易于使用,预训练完词向量之后可以直接通过查“词典”来使用,但是缺点也很明显,比如一词多义怎么办?一个token只有一个固定的向量。
另一些则是需要在句子中才能将词向量具体化,比如bert和xlnet。这样词向量就不是一个具体的词向量了,在不同的语境中一个单词可以有不同的意思。缺点是比较消耗资源,太贵。