4. 文本自然语言处理数据集

目前本项目已集成6个数据集,即

  1. amazon_reviews_multi 的中文部分(记为 amazon_reviews_zh

  2. SST

  3. imdb_reviews 带标签数据的一小部分(记为 imdb_reviews_tiny

  4. dianping 的一小部分(记为 dianping_tiny

  5. jd_binary 的一小部分(记为 jd_binary_tiny

  6. jd_full 的一小部分(记为 jd_full_tiny

4.1. amazon_reviews_multi

该数据集收集了产生亚马逊(Amazon)自2015.11.1至2019.11.1的商品评论,涵盖中文,英文等共6种语言。数据集中每一条记录包含了商品评论的文本,标题,星标(1-5星),评论者的匿名ID,商品的匿名ID,以及粗粒度的商品品类。每一种语言在训练集、验证集、测试集中都分别有200000、5000以及5000条数据。以下是某条中文的数据:

{
    "language": "zh",
    "product_category": "book",
    "product_id": "product_zh_0123483",
    "review_body": "这简直就是太差了!出版社怎么就能出版吗?我以为是百度摘录呢!这到底是哪个鱼目混珠的教授啊?!能给点干货吗?!总算应验了一句话,一本书哪怕只有一句花你感到有意义也算是本好书。哇为了找这本书哪怕一句不是废话的句子都费了我整整一天时间。。",
    "review_id": "zh_0713738",
    "review_title": "简直是废话!",
    "reviewer_id": "reviewer_zh_0518940",
    "stars": 1
}

4.2. amazon_reviews_zh

language 字段为 zh 的部分抽取出来,共计210000条,放入一个 DataFrame 中,保存为 csv 文件,并用 gzip 压缩,大小为19.4M。目前这个数据集保存在 text/Datasets/amazon_reviews_zh 下。具体从 Huggingface 的软件包 datasets 生成的代码如下:

import datasets
import pandas as pd
ar_zh = datasets.load_dataset("amazon_reviews_multi", "zh")
cols = ["set", "product_category", "product_id", "review_body", "review_id", "review_title", "reviewer_id", "stars",]
temp = []
for s in ["train", "validation", "test"]:
    for item in ar_zh[s]:
        c = {"set":s}
        c.update(item)
        temp.append(c)
ar_zh = pd.DataFrame(temp)
ar_zh = ar_zh[cols]

4.3. SST

数据集 SST 全称为 Stanford Sentiment Treebank ,是一个英文的影评数据集,共有11855条数据,每一条数据形如

{
    "label": 0.7222200036048889,
    "sentence": "Yet the act is still charming here .",
    "tokens": "Yet|the|act|is|still|charming|here|.",
    "tree": "15|13|13|10|9|9|11|12|10|11|12|14|14|15|0"
}

其中,每一个字段意义如下

  • sentence: 关于一部电影的一条评论

  • label: 这条评论的正面性的程度,值的范围为0.0到1.0

  • tokens: 从这条评论得到的tokens

  • tree: 利用句法解析得到的这条评论的句法树

目前这个数据集保存在 text/Datasets/sst 下。具体从 Huggingface 的软件包 datasets 生成的代码如下:

import datasets
import pandas as pd
sst = datasets.load_dataset("sst")
cols = ["set", "label", "sentence", "tokens", "tree",]
temp = []
for s in ["train", "validation", "test"]:
    for item in sst[s]:
        c = {"set":s}
        c.update(item)
        temp.append(c)
sst = pd.DataFrame(temp)
sst = sst[cols]

4.4. imdb_reviews

该数据集主要是IMDB上的影评,标签为影评为负面评价(0)、正面评价(1),分为了训练集、测试集,分别有25000条数据。此外还有50000条未带标签(-1)的数据。要注意的是,原始数据的文本中可能带有HTML标签。

{
    "label": 0,
    "text": "Mann photographs the Alberta Rocky Mountains in a superb fashion, and Jimmy Stewart and Walter Brennan give enjoyable performances as they always seem to do. <br /><br />But come on Hollywood - a Mountie telling the people of Dawson City, Yukon to elect themselves a marshal (yes a marshal!) and to enforce the law themselves, then gunfighters battling it out on the streets for control of the town? <br /><br />Nothing even remotely resembling that happened on the Canadian side of the border during the Klondike gold rush. Mr. Mann and company appear to have mistaken Dawson City for Deadwood, the Canadian North for the American Wild West.<br /><br />Canadian viewers be prepared for a Reefer Madness type of enjoyable howl with this ludicrous plot, or, to shake your head in disgust."
}

4.5. imdb_reviews_tiny

imdb_reviews 的训练集、测试集分别随机抽取1000条正面评价样本与1000条负面评价样本,共计4000条,我们构建了一个小型的数据集 imdb_reviews_tiny,代码如下

import pandas as pd
import tensorflow_datasets as tfds
from random import sample

ds = tfds.text.IMDBReviews()
ds.download_and_prepare()

imdb_train = tfds.load(name="imdb_reviews", split="train")
imdb_test = tfds.load(name="imdb_reviews", split="test")
df_imdb_train = tfds.as_dataframe(imdb_train)
df_imdb_test = tfds.as_dataframe(imdb_test)

df_imdb_train["set"] = "train"
df_imdb_test["set"] = "test"
df_imdb = pd.concat([df_imdb_train,df_imdb_test]).reset_index(drop=True)
df_imdb = df_imdb[["set", "label", "text",]]
train_0 = df_imdb[(df_imdb["set"]=="train") & (df_imdb["label"]==0)].index.tolist()
train_1 = df_imdb[(df_imdb["set"]=="train") & (df_imdb["label"]==1)].index.tolist()
test_0 = df_imdb[(df_imdb["set"]=="test") & (df_imdb["label"]==0)].index.tolist()
test_1 = df_imdb[(df_imdb["set"]=="test") & (df_imdb["label"]==1)].index.tolist()
imdb_tiny_indices = sorted(sample(train_0, 1000) + sample(train_1, 1000) + sample(test_0, 1000) + sample(test_1, 1000))
df_imdb_tiny = df_imdb[df_imdb.index.isin(imdb_tiny_indices)].reset_index(drop=True)
df_imdb_tiny["text"] = df_imdb_tiny["text"].apply(lambda s:s.decode())

目前这个数据集保存在 text/Datasets/imdb_reviews_tiny 下。

4.6. dianping

数据集 dianping 收集自大众点评的商品、店铺评论数据,共计两百余万条,字段有 label (1,2),以及 text,源自 Glyph 项目 1。示例数据如下

{
    "label": 0,
    "text": "嗓子疼,super带我去黄振龙喝斑莎凉茶。你说我肯定不能一口气喝下这么苦的东西,我像个小孩子一样,为了表现自己,一口气喝完了,然后撇着嘴找你要橘皮吃。你疼爱地望着我,一边骂我“变态的”一边夸我厉害。\\n事后我说没胃口闹着要吃湘菜,于是你带到这家店,环境好奇怪哦,更像是一个西餐厅,挂着一些线帘,红沙发。已经忘了吃的什么了。吃完饭我们一路走去人民公园,途径7仔还买了一杯思乐冰,我们像两个小孩一样坐在人民公园的长凳上把这杯思乐冰给吸完了。\\nsuper,never ever"
}

4.7. dianping_tiny

dianping 的训练集、测试集分别随机抽取2500条正面评价样本与2500条负面评价样本,共计10000条,我们构建了一个小型的数据集 dianping_tiny,保存在 text/Datasets/imdb_reviews_tiny 下。该数据集还通过限定 text 字段的长度,分别有 long 版本(长度≥30)以及 xl 版本(长度≥100)。从数据集 dianping 生成 dianping_tiny 的代码如下

from typing import Sequence
from itertools import product

def selection(df:pd.DataFrame, cols:Sequence[str], num:int) -> pd.DataFrame:
    """
    """
    col_sets = product(*[set(df[c].tolist()) for c in cols])
    df_out = pd.DataFrame()
    for combination in col_sets:
        df_tmp = df.copy()
        for c,v in zip(cols, combination):
            df_tmp = df_tmp[df_tmp[c]==v]
        df_tmp = df_tmp.sample(n=min(num,len(df_tmp))).reset_index(drop=True)
        df_out = pd.concat([df_out, df_tmp], ignore_index=True)
    return df_out

df_dp_train = pd.read_csv("dianping-train.csv.xz", header=None)
df_dp_test = pd.read_csv("dianping-test.csv.xz", header=None)
df_dp_train.columns = ["label", "text",]
df_dp_test.columns = ["label", "text",]
df_dp_train["set"] = "train"
df_dp_test["set"] = "test"

df_dp = pd.concat([df_dp_train,df_dp_test], ignore_index=True)
df_dp = df_dp[["set", "label", "text",]]
df_dp = df_dp[df_dp.text.str.contains("[\u4e00-\u9FFF]+")].reset_index(drop=True)

df_dp_tiny = selection(df_dp, cols=["set", "label"], num=2500).sample(frac=1)
df_dp_tiny.to_csv("dianping_filtered_tiny.csv.gz", index=False, compression="gzip")

df_dp_long_tiny = selection(df_dp[df_dp.text.str.len()>=30], cols=["set", "label"], num=2500).sample(frac=1)
df_dp_long_tiny.to_csv("dianping_filtered_long_tiny.csv.gz", index=False, compression="gzip")

df_dp_xl_tiny = selection(df_dp[df_dp.text.str.len()>=100], cols=["set", "label"], num=2500).sample(frac=1)
df_dp_xl_tiny.to_csv("dianping_filtered_xl_tiny.csv.gz", index=False, compression="gzip")

4.8. jd_full

数据集 jd_full 收集自京东的商品评论数据,共计四十余万条,字段有 score (1 - 5),以及 title, content,源自 Glyph 项目 1。示例数据如下

{
    "score": 5,
    "title": "旋涡猫的找法:村上朝日堂日记(新版)",
    "text": "马拉松这东西,在某种意义上是相当奇异的体验。我甚至觉得人生本 身的色彩都会因体验和没体验过马拉松而大不相同。尽管不能说是宗教体 验,但其中仍有某种与人的存在密切相关的东西。实际跑四十二公里的途 中,难免相当认真地自己问自己:我何苦这么自找苦吃?不是什么好处都 没有吗?或者不如说反倒对身体不利(脱趾甲、起水泡、第二天下楼难受) 。可是等到好歹冲进终点、喘一口气接过冰凉的罐装啤酒&ldquo;咕嘟嘟&rdquo;喝下 去进而泡进热水里用别针尖刺破胀鼓鼓的水泡的时候,又开始满怀豪情地 心想:下次一定再跑!这到底是什么作用呢?莫非人是时不时怀有潜在的 愿望,存心要把自己折磨到极点不成? 其形成原由我不大清楚,反正这种感受是只能在跑完全程马拉松时才 能出现的特殊感受。说来奇怪,即使跑半程马拉松也没有如此感受,无非 &ldquo;拼命跑完二十一公里&rdquo;而已。诚然,半程说辛苦也够辛苦的,但那是跑 完时即可整个消失的辛苦。而跑完全程马拉松时,就有无法简单化解的执 著的东西在人的(至少我的)心头挥之不去。解释是解释不好,感觉上就好 像不久还将遭遇刚刚尝过的痛苦,因而必须相应做一下&ldquo;善后处理&rdquo;&mdash;&mdash; &ldquo;这个还要重复的,这回得重复得好一些才行!&rdquo;正因如此,前后十二年 时间里我才不顾每次都累得气喘吁吁筋疲力尽而不屈不挠坚持跑全程马拉 松&mdash;&mdash;当然&ldquo;善后处理&rdquo;是一点也没处理好。 或许有人说是自虐,但我认为绝不是仅仅如此,莫如说类似一种好奇 心,类似一种力图通过一次次增加次数一点点提高限度来把自己身上潜在 的、自己尚不知晓而想一睹为快的东西一把拉到光天化日之下的心情&hellip;&hellip; 细想之下,这同我平时对长篇小说怀有的心情几乎一模一样。某一天 突然动了写长篇小说的念头,于是坐在桌前,数月或数年屏息敛气将精神 集中在极限状态,终于写出一部长篇。每次都累得像狠狠拧过的抹布,啊 ,太累了,累死了!心想再不干那种事了。不料时过不久,再次心血来潮 :这回可要大干一场!又死皮赖脸地坐在桌前动笔写长篇。然而无论怎么 写无论写多少都仍有凝结物沉甸甸地残留在肚子里。 相比之下,短篇小说就好像十公里赛,再长不过是半程马拉松罢了。 不用说,短篇自有短篇的独特作用,自有其相应的文思和愉悦,但缺乏&mdash; &mdash;当然是对我而言&mdash;&mdash;深深触及身体结构本身的那种决定性的致命性质的 东西,因而&ldquo;爱憎参半&rdquo;的东西也少于长篇。 马拉松跑完后,去终点附近科普利广场里面的波士顿最有名的海鲜餐 厅&ldquo;LEAGAL SEAFOOD&rdquo;喝蚬肉汤,吃一种惟独新英格兰地区才有的我喜欢 吃的海贝。女侍应生看着我手中跑完全程的纪念章夸奖道:&ldquo;你跑马拉松 了?嗬,好有勇气啊!&rdquo;非我瞎说,被人夸有勇气有生以来差不多是头一 次。说实话,我根本没什么勇气。 但不管谁怎么说,有勇气也好没勇气也好,跑完全程马拉松之后吃的 足够量的热气腾腾的晚餐,实在是这个世界上最美妙的东西之一。 不管谁怎么说。P10-13\\n"
}

4.9. jd_full_tiny

jd_full 的训练集、测试集分别随机抽取1000条1-5分(score)样本,共计10000条,我们构建了一个小型的数据集 jd_full_tiny,保存在 text/Datasets/jd_full_tiny 下。该数据集还通过限定 content 字段的长度,分别有 long 版本(长度≥30)以及 xl 版本(长度≥100)。从数据集 jd_full 生成 jd_full_tiny 的代码如下

df_jd_full_train = pd.read_csv("jd_full_train.csv.xz", header=None)
df_jd_full_test = pd.read_csv("jd_full_test.csv.xz", header=None)
df_jd_full_train.columns = ["score", "title", "content",]
df_jd_full_test.columns = ["score", "title", "content",]
df_jd_full_train["set"] = "train"
df_jd_full_test["set"] = "test"

df_jd_full = pd.concat([df_jd_full_train,df_jd_full_test], ignore_index=True)
df_jd_full = df_jd_full[["set", "score", "title", "content",]]
df_jd_full = df_jd_full[df_jd_full.text.str.contains("[\u4e00-\u9FFF]+")].reset_index(drop=True)

df_jd_full_tiny = selection(df_jd_full, cols=["set", "score"], num=1000).sample(frac=1)
df_jd_full_tiny.to_csv("jd_full_filtered_tiny.csv.gz", index=False, compression="gzip")

df_jd_full_long_tiny = selection(df_jd_full[df_jd_full.text.str.len()>=30], cols=["set", "score"], num=1000).sample(frac=1)
df_jd_full_long_tiny.to_csv("jd_full_filtered_long_tiny.csv.gz", index=False, compression="gzip")

df_jd_full_xl_tiny = selection(df_jd_full[df_jd_full.text.str.len()>=100], cols=["set", "score"], num=1000).sample(frac=1)
df_jd_full_xl_tiny.to_csv("jd_full_filtered_xl_tiny.csv.gz", index=False, compression="gzip")

4.10. jd_binary

数据集 jd_binary 是将 jd_fullscore 字段(1 - 5)变为2类(1,2),替换为 label 字段得到的,源自 Glyph 项目 1

4.11. jd_binary_tiny

从数据集 jd_binary 获得数据集 jd_binary_tiny 的方式,与数据集 dianping_tinydianping_tiny )以及数据集 jd_full_tinyjd_full_tiny )的生成方式类似。

1(1,2,3)

Zhang X, LeCun Y. Which encoding is the best for text classification in chinese, english, japanese and korean?[J]. arXiv preprint arXiv:1708.02657, 2017.