情感分析与酒店评论——处理数据


文档摘要

情感分析与酒店评论——处理数据 在本节中,你将使用前几课中学到的技术对一个大型数据集进行探索性数据分析。一旦你很好地理解了各个列的有用性,你将学习: 如何删除不必要的列 如何基于现有列计算一些新数据 如何保存最终挑战中使用的数据集 课前测验 引言 到目前为止,你已经了解了文本数据与数值型数据非常不同。如果这是人类写的或说的文字,可以对其进行分析以找出模式和频率、情感和意义。本课程将带你进入一个真实的数据集,并面临真正的挑战:欧洲515K酒店评论数据,该数据集包含CC0: 公有领域许可。它从Booking.com上公开获取。数据集的创建者是Jiashen Liu。 准备工作 你需要以下内容: 使用Python 3运行.

情感分析与酒店评论——处理数据

在本节中,你将使用前几课中学到的技术对一个大型数据集进行探索性数据分析。一旦你很好地理解了各个列的有用性,你将学习:

  • 如何删除不必要的列
  • 如何基于现有列计算一些新数据
  • 如何保存最终挑战中使用的数据集

课前测验

引言

到目前为止,你已经了解了文本数据与数值型数据非常不同。如果这是人类写的或说的文字,可以对其进行分析以找出模式和频率、情感和意义。本课程将带你进入一个真实的数据集,并面临真正的挑战:欧洲515K酒店评论数据,该数据集包含CC0: 公有领域许可。它从Booking.com上公开获取。数据集的创建者是Jiashen Liu。

准备工作

你需要以下内容:

  • 使用Python 3运行.ipynb笔记本的能力
  • pandas
  • NLTK,请在本地安装
  • 数据集可以在Kaggle上下载,名为**欧洲515K酒店评论数据**。解压后大约230MB。将其下载到这些NLP课程关联的根/data文件夹。

探索性数据分析

这个挑战假设你正在使用情感分析和客人评论评分构建一个酒店推荐机器人。你将使用的数据集包括6个城市中的1493家酒店的评论。

使用Python、酒店评论数据集和NLTK的情感分析,你可以发现:

  • 评论中最常用的单词和短语是什么?
  • 官方描述酒店的标签是否与评论评分相关(例如,是否有更多的负面评论针对家庭带小孩而不是独自旅行者,这可能表明酒店更适合独自旅行者)?
  • NLTK的情感评分与酒店评论者的数字评分是否一致?

数据集

让我们来探索一下你下载并保存在本地的数据集。在像VS Code这样的编辑器或甚至Excel中打开该文件。

数据集中的标题如下:

酒店地址, 评分人数额外计数, 评论日期, 平均评分, 酒店名称, 评论者国籍, 负面评论, 负评词数总计, 总评论数, 正面评论, 正评词数总计, 评论者给出的总评论数, 评论者评分, 标签, 评论距今天数, 纬度, 经度

以下是分组后的标题,便于查看:

酒店列

*Hotel_Name, Hotel_Address, lat (纬度), lng (经度)

  • 使用纬度经度,你可以用Python绘制一张显示酒店位置的地图(可能用不同的颜色表示负面和正面评论)
  • 酒店地址对我们来说显然不太有用,我们可能会用国家来代替,以便更容易排序和搜索

酒店元评论列

*Average_Score

  • 根据数据集创建者所述,此列是“根据最近一年内最新评论计算的酒店平均评分”。这种计算方式似乎不寻常,但这是抓取的数据,目前我们可以接受它。

✅ 基于数据集中的其他列,你能想到另一种计算平均评分的方法吗?

*Total_Number_of_Reviews

  • 这个酒店收到的总评论数——不清楚(不写代码的话)这是否指的是数据集中的评论。
    *Additional_Number_of_Scoring
  • 这意味着虽然给出了评论评分,但没有写出正面或负面评论。

评论列

  • Reviewer_Score
    • 这是一个最多保留一位小数的数值,范围在2.5到10之间
    • 不清楚为什么2.5是最底分
  • Negative_Review
    • 如果评论者什么也没写,这个字段将显示“无负面”
    • 注意,评论者可能会在负面评论栏写正面评论(例如,“这个酒店没有任何不好的地方”)
  • Review_Total_Negative_Word_Counts
    • 较高的负面词数表明较低的评分(不检查情感)
  • Positive_Review
    • 如果评论者什么也没写,这个字段将显示“无正面”
    • 注意,评论者可能会在正面评论栏写负面评论(例如,“这个酒店完全没有好东西”)
  • Review_Total_Positive_Word_Counts
    • 较高的正面词数表明较高的评分(不检查情感)
  • Review_Datedays_since_review
    • 可能会对评论进行新鲜度或陈旧度衡量(较旧的评论可能不如新的准确,因为酒店管理变更、装修完成或添加了泳池等)
  • Tags
    • 这些是评论者可以选择的简短描述,以描述他们属于哪种类型的客人(例如,单独或家庭),他们住的是哪种房间,逗留时间以及如何提交评论。
    • 不幸的是,使用这些标签是有问题的,请参阅下面讨论其效用的部分

评论者列

  • Total_Number_of_Reviews_Reviewer_Has_Given
    • 这可能是推荐模型的一个因素,例如,如果可以确定评论数量多的评论者更有可能是负面而不是正面的。然而,任何特定评论的评论者都没有唯一的标识码,因此无法将它们链接到一组评论。有30位评论者至少写了100条评论,但很难看出这对推荐模型有什么帮助。
  • Reviewer_Nationality
    • 有些人可能会认为某些国家的人更有可能给出积极或消极的评论,因为他们有一种民族倾向。在建立模型时要小心不要把这些观点带进去。这些是民族(有时是种族)刻板印象,每位评论者都是基于他们的个人体验写评论的。这可能通过许多透镜过滤,比如他们之前的酒店住宿经历、旅行距离和个人气质。认为评论分数是因为他们的国籍而给出的观点难以成立。
示例
平均评分 总评论数 评论者评分 负面评论 正面评论 标签
7.8 1945 2.5 目前这里不是一个酒店,而是一个建筑工地。我在早晨和整天都被不可接受的施工噪音困扰,而我需要休息和在房间里工作。人们整天都在隔壁房间用风镐工作。我要求换房间,但没有安静的房间可用。更糟糕的是,我被超额收费了。我晚上退房,因为第二天早上要赶飞机,收到了合适的账单。一天后,酒店在未经我同意的情况下再次收费,超过预订价格。这是一个糟糕的地方。不要惩罚自己,来这里预订吧。 没有负面的地方。离开吧 商务旅行,情侣,标准双人间,住了2晚

如你所见,这位客人在这个酒店没有愉快的经历。这家酒店有7.8的好平均评分和1945条评论,但这位评论者只给了2.5分,并写了115个词来描述他的负面体验。如果他在正面评论栏里什么都没写,你可能会认为没有什么积极的,但遗憾的是他写了7个字的警告。如果我们仅凭词语数量而不是情感来判断,我们可能会对评论者的意图产生偏见。奇怪的是,他的评分2.5令人困惑,因为如果酒店住宿这么差,为什么还要给它任何分数呢?仔细研究数据集,你会发现最低可能的分数是2.5,而不是0。最高可能的分数是10。

标签

如上所述,乍一看,使用Tags来分类数据的想法是有道理的。不幸的是,这些标签并不标准化,这意味着在某个酒店,选项可能是单人间双人间大床房,而在下一个酒店,它们可能是豪华单人间经典皇后房行政大床房。这些可能是相同的东西,但由于存在如此多的变化,选择变成了:

  1. 尝试将所有术语转换为单一标准,这非常困难,因为在每种情况下都不清楚转换路径是什么(例如,经典单人间映射到单人间,但带庭院花园或城市景观的豪华皇后房则更难映射)

  2. 我们可以采用NLP方法,测量某些术语(如单独商务旅客带小孩的家庭)在每个酒店的应用频率,并将其纳入推荐

标签通常(但不总是)是一个字段,包含5到6个用逗号分隔的值,对应于旅行类型客人类型房间类型住宿天数评论提交设备。但是,由于一些评论者没有填写每个字段(他们可能会留空),这些值并不总是按相同的顺序排列。

例如,考虑团体类型。在Tags列中,这个字段有1025个独特的可能性,但不幸的是,其中只有部分涉及团体(有些是房间类型等)。如果你只过滤提到家庭的结果,结果会包含很多家庭房类型的结果。如果你包括这个词,即计算带小孩的家庭的值,结果会更好,有超过80,000个结果包含“带小孩的家庭”或“带大孩子家庭”的短语。

这意味着标签列并不是完全无用的,但它需要一些工作才能变得有用。

平均酒店评分

数据集中有一些奇怪的差异,我无法解释,但在这里展示出来,以便你在构建模型时知道它们的存在。如果你发现了,请在讨论部分告诉我们!

数据集中有以下与平均评分和评论数量相关的列:

  1. 酒店名称
  2. 评分人数额外计数
  3. 平均评分
  4. 总评论数
  5. 评论者评分

数据集中评论最多的单个酒店是英国国际酒店坎宁安码头,共有4789条评论,占515,000条。但如果我们查看该酒店的Total_Number_of_Reviews值,它是9086。你可能会猜测有很多评论没有文字,所以我们应该加上Additional_Number_of_Scoring列的值。该值为2682,加上4789得到7471,仍比Total_Number_of_Reviews少1615。

如果你查看Average_Score列,你可能会猜测这是数据集中评论的平均值,但Kaggle的描述是“根据最近一年内最后一条评论计算的酒店平均评分”。这似乎不太有用,但我们可以通过数据集中的评论分数计算自己的平均值。以同一酒店为例,平均酒店评分为7.1,但计算得出的评分(数据集中评论者的平均评分)为6.8。这两个值很接近,但并不相同,我们只能猜测数据集中Additional_Number_of_Scoring评论的评分增加了平均值到7.1。不幸的是,没有办法测试或证明这一说法,因此很难使用或信任Average_ScoreAdditional_Number_of_ScoringTotal_Number_of_Reviews,因为它们基于或引用了我们没有的数据。

更复杂的是,评论数第二多的酒店计算出的平均评分是8.12,而数据集的Average_Score是8.1。这是正确的评分是巧合还是第一个酒店有问题?

考虑到这些酒店可能是异常值,也许大多数值是一致的(但出于某种原因不一致),接下来我们将编写一个小程序来探索数据集中的值,并确定正确使用(或不使用)这些值的方式。

注意事项

在处理此数据集时,你将编写代码从文本中计算某些内容,而无需阅读或分析文本本身。这是NLP的本质,即在不需要人工参与的情况下解释意义或情感。然而,你可能会读到一些负面评论。我建议你不要这样做,因为没有必要。其中一些是愚蠢的或无关紧要的负面酒店评论,例如“天气不好”,这是酒店无法控制的事情,甚至任何人都无法控制。但有些负面评论也有黑暗的一面。有时负面评论带有种族主义、性别歧视或年龄歧视。这是不幸的,但在从公共网站抓取的数据集中是可以预期的。有些评论者留下的评论会让你觉得不舒服、不安或伤心。最好让代码衡量情感,而不是你自己去读它们并感到不安。也就是说,写这种内容的人是少数,但它们确实存在。

练习 - 数据探索

加载数据

现在你有足够的机会观察数据了,接下来你会编写一些代码并得到答案!本节使用pandas库。你的第一个任务是确保可以加载并读取CSV数据。pandas库有一个快速的CSV加载器,结果会被放置在一个数据框中,就像前面的课程一样。我们要加载的CSV文件有超过50万行,但只有17列。pandas提供了许多强大的方式与数据框交互,包括能够对每一行执行操作。

从这里开始,本课将包含代码片段和一些代码解释以及对结果含义的讨论。使用包含的_notebook.ipynb_文件进行编码。

让我们从加载你要使用的数据文件开始:

# Load the hotel reviews from CSV import pandas as pd import time # importing time so the start and end time can be used to calculate file loading time print("Loading data file now, this could take a while depending on file size") start = time.time() # df is 'DataFrame' - make sure you downloaded the file to the data folder df = pd.read_csv('../../data/Hotel_Reviews.csv') end = time.time() print("Loading took " + str(round(end - start, 2)) + " seconds")

现在数据已加载,我们可以对其进行一些操作。请将这段代码保留在你的程序顶部,以供后续使用。

探索数据

在这种情况下,数据已经是干净的,这意味着它已经准备好使用,没有其他语言字符可能干扰期望只有英文字符的算法。

✅ 你可能需要对需要先进行预处理以使其格式化才能应用NLP技术的数据进行处理,但这次不需要。如果有非英文字符,你会怎么处理?

花点时间确保一旦数据加载完毕,你可以使用代码进行探索。很容易想专注于Negative_ReviewPositive_Review列。它们充满了自然文本,供你的NLP算法处理。但是等等!在跳入NLP和情感分析之前,你应该遵循下面的代码来确认数据集中给出的值是否与使用pandas计算的值相符。

数据框操作

本课的第一个任务是通过编写检查数据框的代码(而不改变它)来验证以下断言是否正确。

和许多编程任务一样,有许多方法可以完成这项工作,但一个好的建议是尽可能简单、最容易的方式,尤其是如果将来需要重新理解这段代码时。对于数据框,通常有一个全面的API,经常会有高效完成你想要的操作的方法。
把以下问题当作编程任务,尝试在不看解决方案的情况下回答它们。1. 打印出刚刚加载的数据框的形状(形状是指行数和列数)2. 计算评论者国籍的频率计数:1. 列Reviewer_Nationality有多少不同的值,它们是什么?2. 数据集中最常见的评论者国籍是什么(打印国家和评论次数)3. 数据集中接下来最常出现的10个国家及其频率计数?3. 每个评论者国籍前十名中最常被评论的酒店是什么?4. 数据集中每家酒店的评论次数(酒店的频率计数)是多少?5. 虽然数据集中每个酒店都有一个Average_Score列,你也可以计算一个平均评分(获取数据集中每个酒店的所有评论者评分的平均值)。向你的数据框中添加一个新列,标题为Calc_Average_Score,包含该计算的平均值。6. 是否有任何酒店的(四舍五入到一位小数)Average_ScoreCalc_Average_Score相同?7. 计算并打印有多少行的Negative_Review值为"No Negative"(无负面)。8. 计算并打印有多少行的Negative_Review值为"No Positive"(无正面)。
行具有列 Positive_Review 值为"No Positive"的9行。计算并打印出行具有列 Positive_Review 值为"No Positive" Negative_Review 值为"No Negative"的数量。

代码答案

  1. 打印出你刚刚加载的数据框的形状(形状是行数和列数)。

    print("The shape of the data (rows, cols) is " + str(df.shape)) > The shape of the data (rows, cols) is (515738, 17)
  2. 计算评论者国籍的频率计数:

    1. Reviewer_Nationality 有多少不同的值,它们是什么?
    2. 数据集中最常见的评论者国籍是什么(打印国家和评论数量)?

    value_counts() creates a Series object that has index and values in this case, the country and the frequency they occur in reviewer nationality

    nationality_freq = df["Reviewer_Nationality"].value_counts()
    print("There are " + str(nationality_freq.size) + " different nationalities")

    print(nationality_freq)

    There are 227 different nationalities
    United Kingdom 245246
    United States of America 35437
    Australia 21686
    Ireland 14827
    United Arab Emirates 10235
    ...
    Comoros 1
    Palau 1
    Northern Mariana Islands 1
    Cape Verde 1
    Guinea 1
    Name: Reviewer_Nationality, Length: 227, dtype: int64

  3. 下一个最常见的10个国籍及其频率计数是什么?

    print("The highest frequency reviewer nationality is " + str(nationality_freq.index[0]).strip() + " with " + str(nationality_freq[0]) + " reviews.") # Notice there is a leading space on the values, strip() removes that for printing # What is the top 10 most common nationalities and their frequencies? print("The next 10 highest frequency reviewer nationalities are:") print(nationality_freq[1:11].to_string()) The highest frequency reviewer nationality is United Kingdom with 245246 reviews. The next 10 highest frequency reviewer nationalities are: United States of America 35437 Australia 21686 Ireland 14827 United Arab Emirates 10235 Saudi Arabia 8951 Netherlands 8772 Switzerland 8678 Germany 7941 Canada 7894 France 7296
  4. 对于前10个最常见的评论者国籍,每个国籍最常评论的酒店是什么?

    # What was the most frequently reviewed hotel for the top 10 nationalities # Normally with pandas you will avoid an explicit loop, but wanted to show creating a new dataframe using criteria (don't do this with large amounts of data because it could be very slow) for nat in nationality_freq[:10].index: # First, extract all the rows that match the criteria into a new dataframe nat_df = df[df["Reviewer_Nationality"] == nat] # Now get the hotel freq freq = nat_df["Hotel_Name"].value_counts() print("The most reviewed hotel for " + str(nat).strip() + " was " + str(freq.index[0]) + " with " + str(freq[0]) + " reviews.") The most reviewed hotel for United Kingdom was Britannia International Hotel Canary Wharf with 3833 reviews. The most reviewed hotel for United States of America was Hotel Esther a with 423 reviews. The most reviewed hotel for Australia was Park Plaza Westminster Bridge London with 167 reviews. The most reviewed hotel for Ireland was Copthorne Tara Hotel London Kensington with 239 reviews. The most reviewed hotel for United Arab Emirates was Millennium Hotel London Knightsbridge with 129 reviews. The most reviewed hotel for Saudi Arabia was The Cumberland A Guoman Hotel with 142 reviews. The most reviewed hotel for Netherlands was Jaz Amsterdam with 97 reviews. The most reviewed hotel for Switzerland was Hotel Da Vinci with 97 reviews. The most reviewed hotel for Germany was Hotel Da Vinci with 86 reviews. The most reviewed hotel for Canada was St James Court A Taj Hotel London with 61 reviews.
  5. 数据集中每个酒店的评论数量是多少(酒店的频率计数)?

    # First create a new dataframe based on the old one, removing the uneeded columns hotel_freq_df = df.drop(["Hotel_Address", "Additional_Number_of_Scoring", "Review_Date", "Average_Score", "Reviewer_Nationality", "Negative_Review", "Review_Total_Negative_Word_Counts", "Positive_Review", "Review_Total_Positive_Word_Counts", "Total_Number_of_Reviews_Reviewer_Has_Given", "Reviewer_Score", "Tags", "days_since_review", "lat", "lng"], axis = 1) # Group the rows by Hotel_Name, count them and put the result in a new column Total_Reviews_Found hotel_freq_df['Total_Reviews_Found'] = hotel_freq_df.groupby('Hotel_Name').transform('count') # Get rid of all the duplicated rows hotel_freq_df = hotel_freq_df.drop_duplicates(subset = ["Hotel_Name"]) display(hotel_freq_df)
    酒店名称 总评论数 在数据集中找到的评论数
    英国国际酒店Canary Wharf 9086 4789
    Park Plaza Westminster Bridge London 12158 4169
    Copthorne Tara Hotel London Kensington 7105 3578
    ... ... ...
    Mercure Paris Porte d Orleans 110 10
    Hotel Wagner 135 10
    Hotel Gallitzinberg 173 8

    您可能会注意到在数据集中计数的结果与 Total_Number_of_Reviews 中的值不匹配。不清楚该数据集中的值是否代表酒店拥有的总评论数,但并非所有评论都被抓取,或者有其他计算。由于这种模糊性,Total_Number_of_Reviews 不用于模型中。

  6. 虽然数据集中每个酒店都有一个 Average_Score 列,但您也可以计算平均分(获取数据集中每个酒店的所有评论者的评分的平均值)。向您的数据框添加一个新列,列头为Calc_Average_Score,包含该计算出的平均值。打印出列 Hotel_NameAverage_ScoreCalc_Average_Score

    # define a function that takes a row and performs some calculation with it def get_difference_review_avg(row): return row["Average_Score"] - row["Calc_Average_Score"] # 'mean' is mathematical word for 'average' df['Calc_Average_Score'] = round(df.groupby('Hotel_Name').Reviewer_Score.transform('mean'), 1) # Add a new column with the difference between the two average scores df["Average_Score_Difference"] = df.apply(get_difference_review_avg, axis = 1) # Create a df without all the duplicates of Hotel_Name (so only 1 row per hotel) review_scores_df = df.drop_duplicates(subset = ["Hotel_Name"]) # Sort the dataframe to find the lowest and highest average score difference review_scores_df = review_scores_df.sort_values(by=["Average_Score_Difference"]) display(review_scores_df[["Average_Score_Difference", "Average_Score", "Calc_Average_Score", "Hotel_Name"]])

    您可能还会对 Average_Score 的值感到好奇,并想知道为什么它有时与计算出的平均分不同。由于我们无法知道为什么有些值匹配,而另一些则有差异,在这种情况下,使用我们拥有的评论分数来计算自己的平均值是最安全的做法。话虽如此,这些差异通常非常小,以下是与数据集平均值偏差最大的酒店:

    平均分差异 平均分 计算平均分 酒店名称
    -0.8 7.7 8.5 Best Western Hotel Astoria
    -0.7 8.8 9.5 Hotel Stendhal Place Vend me Paris MGallery
    -0.7 7.5 8.2 Mercure Paris Porte d Orleans
    -0.7 7.9 8.6 Renaissance Paris Vendome Hotel
    -0.5 7.0 7.5 Hotel Royal Elys es
    ... ... ... ...
    0.7 7.5 6.8 Mercure Paris Op ra Faubourg Montmartre
    0.8 7.1 6.3 Holiday Inn Paris Montparnasse Pasteur
    0.9 6.8 5.9 Villa Eugenie
    0.9 8.6 7.7 MARQUIS Faubourg St Honor Relais Ch teaux
    1.3 7.2 5.9 Kube Hotel Ice Bar

    只有一家酒店的得分差异大于1,这意味着我们可以忽略差异并使用计算出的平均分。

  7. 计算并打印出行具有列 Negative_Review 值为"No Negative"的数量。

  8. 计算并打印出行具有列 Positive_Review 值为"No Positive" Negative_Review 值为"No Negative"的数量。

    # with lambdas: start = time.time() no_negative_reviews = df.apply(lambda x: True if x['Negative_Review'] == "No Negative" else False , axis=1) print("Number of No Negative reviews: " + str(len(no_negative_reviews[no_negative_reviews == True].index))) no_positive_reviews = df.apply(lambda x: True if x['Positive_Review'] == "No Positive" else False , axis=1) print("Number of No Positive reviews: " + str(len(no_positive_reviews[no_positive_reviews == True].index))) both_no_reviews = df.apply(lambda x: True if x['Negative_Review'] == "No Negative" and x['Positive_Review'] == "No Positive" else False , axis=1) print("Number of both No Negative and No Positive reviews: " + str(len(both_no_reviews[both_no_reviews == True].index))) end = time.time() print("Lambdas took " + str(round(end - start, 2)) + " seconds") Number of No Negative reviews: 127890 Number of No Positive reviews: 35946 Number of both No Negative and No Positive reviews: 127 Lambdas took 9.64 seconds

另一种方式

另一种无需使用Lambda函数的方式,可以使用sum来计算行数:

# without lambdas (using a mixture of notations to show you can use both) start = time.time() no_negative_reviews = sum(df.Negative_Review == "No Negative") print("Number of No Negative reviews: " + str(no_negative_reviews)) no_positive_reviews = sum(df["Positive_Review"] == "No Positive") print("Number of No Positive reviews: " + str(no_positive_reviews)) both_no_reviews = sum((df.Negative_Review == "No Negative") & (df.Positive_Review == "No Positive")) print("Number of both No Negative and No Positive reviews: " + str(both_no_reviews)) end = time.time() print("Sum took " + str(round(end - start, 2)) + " seconds") Number of No Negative reviews: 127890 Number of No Positive reviews: 35946 Number of both No Negative and No Positive reviews: 127 Sum took 0.19 seconds

您可能已经注意到有127行在列 Negative_ReviewPositive_Review 分别具有"No Negative"和"No Positive"的值。这意味着评论者给酒店打了一个数值评分,但拒绝写正面或负面评论。幸运的是,这只是一个很小的比例(515738行中的127行,或0.02%),所以它可能不会以任何特定的方向扭曲我们的模型或结果,但您可能没有预料到评论数据集中会有一些没有评论的行,因此探索数据以发现这样的行是值得的。

现在您已经探索了数据集,在下一课中,您将过滤数据并添加一些情感分析。

挑战

本课演示了,正如我们在之前的课程中看到的,理解数据及其特点在对其进行操作之前是多么重要。特别是基于文本的数据需要仔细检查。深入研究各种基于文本的数据集,看看是否可以发现可能导致模型偏差或情感偏斜的区域。

课后测验

复习与自学

请学习此NLP学习路径,以发现构建语音和文本密集型模型时可以尝试的工具。

作业 NLTK

请从左到右写出输出。

声明:
本文件灏天文库团队进行了翻译。尽管我们力求准确,但请注意,翻译可能包含错误或不准确之处。原文档以其原始语言为准。我们不对因使用此翻译而产生的任何误解或误译负责。


作者与出处
原作者: microsoft
来源:microsoft
许可证:MIT
整理: 灏天文库整理
由灏天文库结构化整理,提供目录导航、全文检索与在线阅读,便于系统化学习
发布者: 作者: microsoft 转发
评论区 (0)
U