完整的熊猫指南
构建强大的数据分析流程
数据科学项目中最耗时的部分是数据清理和准备。Pandas 是一个非常强大和通用的 Python 数据分析库,可以加速项目的预处理步骤。在这篇文章中,我将通过许多例子来介绍 Pandas 的许多功能,这些例子可以帮助您构建一个健壮而高效的数据分析过程。
这些主题按如下顺序排列:
- 输入数据
- 数据概述
- 处理缺失值
- 组合数据帧
- 选择数据帧上的数据
- 重塑数据帧
- 其他熊猫功能
Pandas 的基本数据结构是 DataFrame ,它以表格的形式表示数据,带有标记的行和列。
一如既往,我们从进口熊猫开始。
import numpy as np
import pandas as pd
1。输入数据
从文件中读取
在大多数情况下,我们从文件中读取数据并转换成数据帧。Pandas 提供了从许多不同的文件类型中读取数据的功能。最常用的是 read_csv 。其他类型也有,比如 read_excel,read_json,read_html 等等。让我们来看一个使用 read_csv 的例子:
df = pd.read_csv("Churn_Modelling.csv")
df.head()
我们需要指定文件的位置。在文件位于同一个工作目录或文件夹中时,你可以只写文件名。df.head()显示前 5 行。
如果我们只需要数据帧的一部分,而不想读取全部,我们可以用 usecols 参数指定列:
cols = ['CustomerId','CreditScore','NumOfProducts']
df = pd.read_csv("Churn_Modelling.csv", usecols=cols)
df.head()
我们还可以使用 nrows 参数选择要读取多少行。这在处理非常大的文件时非常有用:
df.shape
(10000, 3)df = pd.read_csv("Churn_Modelling.csv", usecols=cols, nrows=500)
df.shape
(500, 3)
原始数据帧有 10000 行,通过将 nrows 设置为 500,我们只读取前 500 行。
read_csv 函数还有许多其他参数,这使它变得强大而方便。
创建数据帧
在现实生活中,我们通常从文件中读取数据,而不是创建数据帧。Pandas 提供了函数来通过从各种文件类型中读取数据来创建数据帧。在这篇文章中,我将使用字典来创建一个示例数据帧。
df = pd.DataFrame({'a':np.random.rand(10),
'b':np.random.randint(10, size=10),
'c':[True,True,True,False,False,np.nan,np.nan,
False,True,True],
'b':['London','Paris','New York','Istanbul',
'Liverpool','Berlin',np.nan,'Madrid',
'Rome',np.nan],
'd':[3,4,5,1,5,2,2,np.nan,np.nan,0],
'e':[1,4,5,3,3,3,3,8,8,4]})
df
2。数据概述
Pandas describe 函数为数值(int 或 float)列提供汇总统计。它计算值的数量,并显示平均值、标准差、最小值和最大值以及 25%、50%和 75%的分位数。
df.describe()
虽然所有的列都有相同的行数,但是 d 列的计数不同,因为 describe 函数不计算 NaN(缺失)值。
value_counts() 以出现次数显示列中的值:
df.c.value_counts()
True 5
False 3
Name: c, dtype: int64
value_counts()不计算 NaN(缺失)值。
我们还应该检查数据类型,并在我们的分析中考虑它们。有些功能只能在某些数据类型上执行。我们可以使用 dtypes 轻松检查数据类型:
df.dtypes
a float64
b object
c object
d float64
e int64
dtype: object
“d”和“e”列都有整数,但“d”列的数据类型是 float。原因是列 d 中的 NaN 值。NaN 值被认为是浮点型的,因此该列中的整数值被向上转换为浮点数据类型。
Pandas 1.0.1 允许使用 NaN 作为整数数据类型。我们只需要显式地将 dtype 表示为 pd。Int64Dtype():
pd.Series([1, 2, 3, np.nan], dtype=pd.Int64Dtype())
0 1
1 2
2 3
3 NaN
dtype: Int64
如果 pd。不使用 Int64Dtype(),整数值被强制转换为浮点数:
pd.Series([1, 2, 3, np.nan])
0 1.0
1 2.0
2 3.0
3 NaN
dtype: float64
3。处理缺失值
处理缺失值是数据清理和准备过程中必不可少的一部分,因为现实生活中几乎所有的数据都带有一些缺失值。
让我们先创建一个缺少值的数据帧。
df = pd.DataFrame({
'column_a':[1, 2, 4, 4, np.nan, np.nan, 6],
'column_b':[1.2, 1.4, np.nan, 6.2 ,None, 1.1, 4.3],
'column_c':['a', '?', 'c', 'd', '--', np.nan, 'd'],
'column_d':[True, True, np.nan, None, False, True, False]
})df
np.nan、None 和 NaT(对于 datetime64[ns]类型)是熊猫的标准缺失值。
**注意:**Pandas 1.0 中引入的一种新的缺失数据类型(< NA >),它是一种整数类型的缺失值表示。
np.nan 是一个浮点数,所以如果你在一列整数中使用它们,它们将被转换成浮点数据类型,正如你在我们创建的数据帧的“column_a”中看到的。但是,可以和整数一起使用,不会导致向上转换。让我们使用向 dataframe 再添加一列,可以通过显式请求 dtype Int64Dtype()来使用它。
new_column = pd.Series([1, 2, np.nan, 4, np.nan, 5], dtype=pd.Int64Dtype())df['column_e'] = new_column
df
熊猫提供了 isnull() 、 isna() 函数来检测缺失值。他们俩做着同样的事情。
df.isna() 返回带有布尔值的 dataframe,该值表示缺少的值。
也可以选择使用与 isna()正好相反的 notna() 。
df.isna()。any() 为每一列返回一个布尔值。如果该列中至少有一个值缺失,则结果为真。
df.isna()。sum() 返回每列中缺失值的数量。
并非所有缺失的值都是简洁明了的 np.nan 或 None 格式。比如,“?”数据帧 c 列中的“—”字符没有给我们任何有价值的信息或见解,因此本质上它们是缺失值。但是,这些字符无法被熊猫检测为缺失值。
如果我们知道哪种字符用作数据集中的缺失值,我们可以在使用 na_values 参数创建数据帧时处理它们:
missing_values = ['?', '--']
df_test = pd.read_csv('filepath.csv', na_values = missing_values)
另一种选择是在创建数据帧后使用 pandas replace() 函数来处理这些值:
df.replace(['?','--'],np.nan, inplace=True)
df
我们已经用 NaN 值替换了非信息单元格。就地参数保存数据帧中的变化。inplace 的默认值为 False,因此如果将其设置为 True,将不会保存更改。
没有处理缺失值的最佳方法。根据数据集和任务的特征,我们可以选择:
- 删除缺少的值
- 替换丢失的值
丢弃缺失值
我们可以使用 dropna() 函数删除缺少值的行或列。如何使用参数将条件设置为下降。
- how='any ':如果有任何缺少的值,则删除
- how='all ':如果所有值都丢失,则删除
此外,使用 thresh 参数,我们可以为丢失的值设置一个阈值,以便删除一行/一列。
df.dropna(axis=0, how='all', inplace=True)
df
轴参数用于选择行(0)或列(1)。
我们的 dataframe 没有一行充满缺失值,因此设置 how='all ‘不会删除任何行。缺省值是’ any ',所以如果我们想使用 how='any ',就不需要指定它:
注意: 原位参数用于保存对原始数据帧的更改。默认值为 false,因此如果我们不将其设置为 True,我们所做的更改将不会保存在原始数据帧中。
将 thresh 参数设置为至少缺少 3 个值的 3 个丢弃行。
数据是宝贵的资产,所以我们不应该轻易放弃它。此外,机器学习模型几乎总是倾向于在更多数据的情况下表现更好。因此,根据具体情况,我们可能更喜欢替换丢失的值,而不是丢弃。
替换缺失值
fillna() 熊猫函数方便处理缺失值。使用 fillna(),缺失值可以由特殊值或聚合值(如平均值、中值)替换。此外,缺失的值可以用它之前或之后的值替换,这对时间序列数据集非常有用。
- 用标量替换丢失的值:
- fillna()也可以用于特定的列:
- 使用方法参数,缺失的值可以用它们之前或之后的值替换。
ffill 代表“向前填充”用前一行中的值替换缺失的值。您也可以选择 bfill 代表“反向填充”。
如果一列或一行中有许多连续的缺失值,您可能希望限制向前或向后填充的缺失值的数量。
极限参数设置为 1,因此只有一个缺失值被向前填充。
4。组合数据帧
Denys Nevozhai 在 Unsplash 拍摄的照片
数据科学项目通常需要我们从不同的来源收集数据。因此,作为数据准备的一部分,我们可能需要组合数据框架。在这一部分,我将讨论以下主题:
- 串联
- 合并
串联
让我们首先创建两个数据帧:
df1 = pd.DataFrame({
'column_a':[1,2,3,4],
'column_b':['a','b','c','d'],
'column_c':[True,True,False,True]
})df2 = pd.DataFrame({
'column_a':[1,2,9,10],
'column_b':['a','k','l','m'],
'column_c':[False,False,False,True]
})
组合或连接数据帧的一种方法是 concat() 函数。通过改变轴参数,它可用于沿行或列连接数据帧。axis 参数的默认值为 0,表示沿行组合。
正如您在上面的第一张图中所看到的,保留了各个数据帧的索引。为了改变它并重新索引组合数据帧, ignore_index 参数设置为真。
concat()函数的 join 参数决定了如何组合数据帧。默认值为“outer ”,返回两个数据帧中的所有索引。如果选择了’ inner '选项,则只返回具有共享索引的行。我将改变 df2 的索引,以便您可以看到“内部”和“外部”的区别。
df = pd.concat([df1,df2], axis=1, join='inner')
df
df = pd.concat([df1,df2], axis=1, join='outer')
df
Pandas 还提供了标记数据帧的方法,以便我们知道哪个部分来自哪个数据帧。我们只是使用键参数按顺序传递组合数据帧列表。
df = pd.concat([df1, df2], keys=['df1', 'df2'])
df
它还使得方便地访问数据帧的不同部分变得更加容易:
关于 concat()函数的一个重要注意事项是,它制作了数据的副本。为了防止进行不必要的复印,需要将复印参数设置为假。默认值为 True。
append() 函数也用于组合数据帧。它可以被看作是 concat()函数的一个特例(axis=0,join='outer '),所以我不会详细讨论它,而只是给出一个例子来展示语法。
df = df1.append(df2)
df
合并
组合数据帧的另一个广泛使用的函数是 merge() 。Concat()函数只是将数据帧一个接一个地相加或并排相加。它更像是附加数据帧。Merge()根据共享列中的值组合数据帧。与 concat()函数相比,Merge()函数提供了更多的灵活性。看到例子就清楚了。
参数上的选择用于合并的列或索引级别。
df_merge = pd.merge(df1, df2, on='column_a')
df_merge
列名不必相同。我们关注的是列中的值。假设两个数据帧在一个列中有共同的值,您希望使用该列来合并这些数据帧,但是列名不同。在这种情况下,可以使用 left_on 和 right_on 参数代替 on 参数。为了显示差异,我将在 df2 中更改列名,然后使用 merge:
df2.rename(columns={'column_a':'new_column_a'}, inplace=True)
df2
df_merge = pd.merge(df1, df2, left_on='column_a', right_on='new_column_a')df_merge
尽管 column_a 和 new_column_a 中的返回值是相同的,但由于具有不同的名称,合并的数据帧包括这两个列。
您也可以将多个值传递给参数上的**。返回的数据帧仅包括在所有传递给参数上的的列中具有相同值的行。**
df2.rename(columns={'new_column_a':'column_a'}, inplace=True)df_merge = pd.merge(df1, df2, on=['column_a','column_b'])
df_merge
df1 和 df2 是根据 column_a 中的公共值合并的,是时候介绍一下howmerge()的参数了。顾名思义,表示你想怎么组合。how 的可能值为“内部”、“外部”、“左侧”、“右侧”。
- inner:只有在参数指定的列中有相同值的行( how 参数的默认值)
- 外部:所有行
- 左侧:左侧数据帧中的所有行
- 右侧:右侧数据帧中的所有行
“如何”的概念在下图中更加清晰。如果您熟悉 SQL,其逻辑与 SQL 连接相同。
下面的数字更清楚地代表了参数的概念。
outer ‘,’ left ‘和’ right '选项包括不在其中一个数据帧中的数据。缺少的部分自动用 NaN 值填充。NaN 是熊猫缺失价值观的典型代表。
how 的默认值是“inner ”,因此您不必在函数中显式编写。“Inner”只返回 column_a 中具有公共值的行。
当 how 参数选择’ outer '时,合并的数据帧包括两个数据帧中 column_a 的所有值。但是,公共值(column_a = 1 和 column_a = 2)不会重复。
当 how 参数选择’ left '时,合并数据帧包括左侧数据帧中所有行。如果 column_a(传递给 on 参数的列)中的值不在右数据帧中,则右数据帧中的列将填充 NaN 值。很少使用“right”选项,因为您只能在 merge 函数中更改数据帧的顺序(而不是(df1,df2)使用(df2,df1))。
您可能已经注意到,两个数据帧中相同的列名会添加一个后缀。区分哪一列来自哪一个数据帧是很有用的。您可以使用后缀参数指定要添加的后缀。
5。选择数据帧上的数据
照片由 Bodie Pyndus 在 Unsplash 上拍摄
iloc 和 loc 允许选择数据帧的一部分。
- iloc:按职位选择
- loc:按标签选择
让我们来看一些例子,因为一如既往,熟能生巧。在本节的示例中,我将使用以下数据帧:
iloc
选择第二行:
df.iloc[1]
a 0.571258
b Paris
c True
d 4
e 4
Name: 1, dtype: object
选择第一行,第二列(即第一行中的第二个值):
df.iloc[0,1]
'London'
所有行,第三列(与选择第二列相同,但我只想展示’:'的用法):
df.iloc[:,2]
0 True
1 True
2 True
3 False
4 False
5 True
7 False
8 True
9 True
Name: c, dtype: bool
前两行,第二列:
df.iloc[:2,1]
0 London
1 Paris
Name: b, dtype: object
loc
最多 2 行,列“b”:
df.loc[:2,'b']
0 London
1 Paris
2 New York
Name: b, dtype: object
最多 2 行和最多“b”列:
df.loc[:2, :'b']
第“2”行和第“b”列:
df.loc[2, :'b']
a 0.16649
b New York
Name: 2, dtype: object
您可能想知道为什么我们在 loc 和 iloc 中对行使用相同的值。原因是数字指数。Loc 按位置选择,但行的位置与索引相同。
让我们创建一个带有非数字索引的新数据帧,这样我们就可以看到不同之处:
index = ['aa','bb','cc','dd','ee']
df2 = pd.DataFrame({'a':np.random.rand(5),
'b':np.random.randint(10, size=5)},
index = index)
df2
df2.loc['bb','b']
1df2.loc[:'cc','a']
aa 0.892290
bb 0.174937
cc 0.600939
Name: a, dtype: float64
6。重塑数据帧
有多种方法可以重塑数据帧。我们可以选择最适合手头任务的一个。重塑数据帧的函数:
- 融化
- 堆叠和拆分
熔化
Melt 用于将宽数据帧转换为窄数据帧。我所说的宽是指具有大量列的数据帧。一些数据帧的结构是连续的测量值或变量用列来表示。在某些情况下,将这些列表示为行可能更适合我们的任务。
考虑以下数据帧:
df1 = pd.DataFrame({'city':['A','B','C'],
'day1':[22,25,28],
'day2':[10,14,13],
'day3':[25,22,26],
'day4':[18,15,17],
'day5':[12,14,18]})
我们有三个不同的城市,在不同的日子进行测量。我们决定用一列中的行来表示这些日子。还会有一列显示测量结果。我们可以通过使用融化功能轻松实现这一点:
df1.melt(id_vars=['city'])
默认情况下,变量和值列的名称是给定的。我们可以使用 melt 函数的参数 var_name 和 value_name 来指定新的列名。如果我们按城市列对数据进行排序,效果会更好:
df1.melt(id_vars=['city'], var_name = 'date', value_name = 'temperature').sort_values(by='city').reset_index(drop=True)
堆叠和取消堆叠
堆栈函数增加了数据帧的索引级别。我所说的提高水平是指:
- 如果 dataframe 有一个简单的列索引,stack 返回一个系列,其索引由原始 dataframe 的行列对组成。
- 如果数据帧有多级索引,stack 增加索引级别。
用例子解释更好。考虑以下数据帧:
df1 有 3 行 6 列,具有简单的整数列索引。如果将 stack 函数应用于 df1,它将返回 3 x 6 = 18 行的序列。序列的索引将是[(0,‘城市’),(0,‘第 1 天’),…,(2,‘第 5 天’)]。
让我们也检查一下形状和指数:
df1.shape
(3,6)
df1.stack().shape
(18,)
df1.stack().index[0] #multilevel index
(0, 'city')
栈和非栈功能更常用于具有多级索引的数据帧。让我们创建一个具有多级索引的数据框架:
tuples = [('A',1),('A',2),('A',3),('B',1),('A',2)]index = pd.MultiIndex.from_tuples(tuples, names=['first','second'])df2 = pd.DataFrame(np.random.randint(10, size=(5,2)),
index=index, columns=['column_x', 'column_y'])
如果我们对该数据帧应用堆栈功能,索引级别将会增加:
df_stacked = df2.stack().to_frame()
df_stacked
现在,列名(column_x 和 column_y)是多级索引的一部分。因此得到的数据帧有一列和一个 3 级多索引。
len(df_stacked.index.levels)
3len(df2.index.levels)
2
拆堆与堆堆正好相反。如果我们对堆叠的数据帧应用拆分,我们将得到原始的数据帧:
df_stacked.unstack().index
MultiIndex(levels=[['A', 'B'], [1, 2, 3]],
codes=[[0, 0, 0, 1, 1], [0, 1, 2, 0, 1]],
names=['first', 'second'])df2.index
MultiIndex(levels=[['A', 'B'], [1, 2, 3]],
codes=[[0, 0, 0, 1, 1], [0, 1, 2, 0, 1]],
names=['first', 'second'])
7.熊猫的其他功能
本部分涵盖的功能:
- 激增
- 努尼克岛
- 检查
- 在哪里
- 推断对象
安德烈·费塔多在 Unsplash 上拍摄的照片
激增
假设您的数据集在单个观测值(行)中包含一个要素的多个条目,但您希望在单独的行中对它们进行分析。
df = pd.DataFrame({'ID':['a','b','c'],
'measurement':[4,6,[2,3,8]],
'day':1})
df
我们希望在单独的行上看到第“1”天“c”的测量值,使用 explode 很容易做到这一点:
df.explode('measurement').reset_index(drop=True)
最好也重置索引:
我们也可以在两列上使用爆炸作为一个链:
df2 = pd.DataFrame({'ID':['a','b','c'],
'measurement_1':[4,6,[2,3,8]],
'measurement_2':[1,[7,9],1],
'day':1})
df2
df2.explode('measurement_1').reset_index(drop=True).explode('measurement_2').reset_index(drop=True)
确保在第一次分解后使用 reset_index,否则会得到如下意外结果:
df2.explode('measurement_1').explode('measurement_2').reset_index(drop=True)
努尼克岛
Nunique 计算列或行中唯一条目的数量。它在分类特征中非常有用,尤其是在我们事先不知道类别数量的情况下。
假设我们有以下数据帧:
要查找列中唯一值的数量:
df.name.nunique()
5
我们可以用稍微复杂一点的语法使用 value_counts 获得相同的结果:
df.name.value_counts().shape[0]
5
然而, nunique 允许我们同时对所有的列或行执行这个操作:
df.nunique() #columns
ID 8
name 5
measurement1 7
measurement2 5
measurement3 6dtype: int64df.nunique(axis=1) #rows
0 3
1 4
2 4
3 5
4 5
5 3
6 4
7 4
dtype: int64
检查
它可用于根据其他行、列对上的值在数据帧中查找值。这个函数最好通过一个例子来解释。假设我们有以下数据帧:
对于每一天,我们有 4 个人的测量值和一个包含这 4 个人的名字的列。我们希望创建一个新列,在“选择”列中显示该人的测量值:
df['Person_point'] = df.lookup(df.index, df['Person'])
df
我们不必对所有数据点都进行这种操作。只要行标签和列标签具有相同的大小,我们就可以使用特定的范围:
df.lookup(df.index[:5], df['Person'][:5])
array([4, 7, 9, 8, 1])
在哪里
“Where”用于根据条件替换行或列中的值。您还可以指定要替换的值。默认值为 NaN。让我们复习一个例子,这样就清楚了。
df['Person_point'].where(df['Person_point'] > 5)0 NaN
1 7.0
2 9.0
3 8.0
4 NaN
5 6.0
6 NaN
7 9.0
Name: Person_point, dtype: float64
我们可以指定替换值:
df['Person_point'].where(df['Person_point'] > 5, 'Not_qualified', inplace=True)df
推断对象
Pandas 支持广泛的数据类型,其中之一是对象。对象包含文本或混合(数字和非数字)值。但是,如果有不同的选项可用,则不建议使用对象数据类型。使用更具体的数据类型可以更快地执行某些操作。例如,我们更喜欢用整数或浮点数据类型来表示数值。
infer_objects 尝试为对象列推断更好的数据类型。我们来看一个例子。
df = pd.DataFrame({'A': ['a', 1, 2, 3],
'B':['b',2.1,1.5,2],
'C':['c',True,False,False],
'D':['a','b','c','d']})
df
df = df[1:]df.dtypes
A object
B object
C object
D object
dtype: object
df.infer_objects().dtypesdf.dtypes
A int64
B float64
C bool
D object
dtype: object
感谢您的阅读。如果您有任何反馈,请告诉我。
使用 Python 的 Scikit-Learn 库的完整推荐系统算法:分步指南
罗伯特·祖尼科夫在 Unsplash 上拍摄的照片
一个简单而有用的算法,只有几行代码
推荐系统的开发可以是自然语言处理(NLP)中的常见任务。YouTube 或网飞使用类似的技术向他们的客户推荐。他们分析客户以前的行为,并在此基础上为他们推荐类似的材料。在本文中,我将讨论如何使用 python 中的 scikit-learn 库开发一个电影推荐模型。它涉及许多复杂的数学。但是 scikit-learn 库有一些很棒的内置函数,可以处理大部分繁重的工作。随着练习的进行,我将解释如何使用这些函数及其工作。
数据集概述
在这个练习中,我将使用一个电影数据集。我在这一页的底部给出了数据集的链接。请随意下载数据集,并在笔记本上运行所有代码,以便更好地理解。以下是数据集的链接:
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/rashida048/Some-NLP-Projects/blob/master/movie_dataset.csv)
以下是电影推荐模型的逐步实现:
- 导入包和数据集。
from sklearn.metrics.pairwise import cosine_similarity
import pandas as pd
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics.pairwise import cosine_similaritydf = pd.read_csv("movie_dataset.csv")
2.数据集太大。因此,我不能在这里显示截图。以下是数据集的列。它们不言自明。列名会告诉你里面的内容是什么。
df.columns#Output:
Index(['index', 'budget', 'genres', 'homepage', 'id', 'keywords', 'original_language', 'original_title', 'overview', 'popularity', 'production_companies', 'production_countries', 'release_date', 'revenue', 'runtime', 'spoken_languages', 'status', 'tagline', 'title', 'vote_average', 'vote_count', 'cast', 'crew', 'director'], dtype='object')
3.选择要用于模型的特征。我们不需要使用所有的功能。有些不适合这个模型。我选择这四个特征:
features = ['keywords','cast','genres','director']
请随意为实验添加更多功能或不同的功能。现在,将这些特征组合起来,用这四列组成一列。
**def** combine_features(row):
**return** row['keywords']+" "+row['cast']+" "+row['genres']+" "+row['director']
4.如果我们有空值,这可能会在算法中产生问题。用空字符串填充空值。
for feature in features:
df[feature] = df[feature].fillna('')
df["combined_features"] = df.apply(combine_features,axis=1)
5.将数据拟合并转换到“计数矢量器”函数中,为矢量表示准备数据。当您通过“计数矢量器”函数传递文本数据时,它会返回每个单词的计数矩阵。
cv = CountVectorizer()
count_matrix = cv.fit_transform(df["combined_features"])
6.使用“余弦相似度”来查找相似度。这是一种寻找相似性的动态方法,该方法测量多维空间中两个向量之间的余弦角。这样,文档的大小就无关紧要了。这些文档可能相距很远,但它们的余弦角可能相似。
cosine_sim = cosine_similarity(count_matrix)
这个“余弦 _sim”是一个二维矩阵,它是一个系数矩阵。我不打算在这里详细解释余弦相似性,因为这超出了本文的范围。我想展示,如何使用它。
7.我们需要定义两个函数。其中一个函数从索引中返回标题,另一个函数从标题中返回索引。我们将很快使用这两个功能。
def find_title_from_index(index):
return df[df.index == index]["title"].values[0]
def find_index_from_title(title):
return df[df.title == title]["index"].values[0]
8.拍一部我们用户喜欢的电影。就拿《星球大战》来说吧。然后用上面的函数找到这部电影的索引。
movie = "Star Wars"
movie_index = find_index_from_title(movie)
《星球大战》的指数是 2912。正如我前面提到的,步骤 6 中的“余弦 _sim”是相似性系数的矩阵。该矩阵的行 2912 应该提供所有具有“星球大战”的电影的相似性系数。所以,找到矩阵‘余弦 _ sim’的第 2912 行。
similar_movies = list(enumerate(cosine_sim[movie_index]))
我使用枚举来获取索引和系数。‘similar _ movies’是包含索引和系数的元组列表。我喜欢在 python 中使用“枚举”。很多时候它会派上用场。
9.按照系数的逆序对列表“相似电影”进行排序。这样,最高的系数将在顶部。
sorted_similar_movies = sorted(similar_movies,key=lambda x:x[1],reverse=True)[1:]
我们没有从列表中选择第一部,因为列表中的第一部将是《星球大战》本身。
10.使用函数“find_title_from_index”获得与“星球大战”相似的前五部电影。
i=0
for element in sorted_similar_movies:
print(find_title_from_index(element[0]))
i=i+1
if i>5:
break
与《星球大战》最相似的五部电影是:
帝国反击战
绝地归来
星球大战:第二集——克隆人的进攻
星球大战:第三集——西斯的复仇
星球大战:第一集——幽灵的威胁
螺旋…加载
有道理,对吧?这就是电影推荐模型。如果你有任何问题,请随时问我。这是我在本教程中使用的数据集。
结论
这个推荐系统非常简单,但是很有用。这种类型的推荐系统在许多现实场景中都很有用。希望你能善用它。
更多阅读:
[## Python 中从头开始的完整异常检测算法:分步指南
基于概率的异常检测算法
towardsdatascience.com](/a-complete-anomaly-detection-algorithm-from-scratch-in-python-step-by-step-guide-e1daf870336e) [## Python 中从头开始的完整 K 均值聚类算法:分步指南
还有,如何使用 K 均值聚类算法对图像进行降维
towardsdatascience.com](/a-complete-k-mean-clustering-algorithm-from-scratch-in-python-step-by-step-guide-1eb05cdcd461) [## 编程、软件工程和数据科学的最佳免费课程
麻省理工、哈佛和斯坦福等顶尖大学的免费课程
towardsdatascience.com](/best-free-courses-for-computer-science-software-engineering-and-data-science-50cd88cafd74) [## 如何在 Python 中呈现多个变量之间的关系
了解如何使用 Python 中的多元图表和绘图来呈现要素之间的关系
towardsdatascience.com](/how-to-present-the-relationships-amongst-multiple-variables-in-python-70f1b5693f5) [## 逻辑回归模型拟合和寻找相关性,P 值,Z 值,置信度…
静态模型拟合和提取的结果从拟合模型使用 Python 的 Statsmodels 库与…
towardsdatascience.com](/logistic-regression-model-fitting-and-finding-the-correlation-p-value-z-score-confidence-8330fb86db19)
一个完整的推荐系统从零开始:一步一步
卡米洛·希门尼斯在 Unsplash 上拍摄的照片
入门
基于用户评分的线性回归电影推荐系统
如今,我们到处都能看到推荐系统。当你在亚马逊、易贝或任何其他地方的在线市场买东西时,他们会推荐类似的产品。在网飞或 youtube 上,你会在你的主页上看到与你之前的活动或搜索相似的建议。他们是如何做到的?他们都遵循这个想法。也就是说,他们从您以前的活动中获取数据,并进行相似性分析。基于这种分析,他们会推荐更多你可能喜欢的产品、视频或电影。
概观
在本文中,我将解释一个使用相同思想的推荐系统。以下是将在此涉及的主题列表:
- 推荐系统的思想和公式。
- 从头开始开发推荐系统算法
- 用那个算法给我推荐电影。
我将使用 Python 的一些库,如 Numpy、Pandas 和 Matplotlib,以提高计算效率和速度。尽管我们的数据集并不太大。但是我们想开发一些适用于更大数据集的东西。我用的是 Jupyter 笔记本环境。随意使用你选择的任何其他笔记本。
这个推荐系统是如何工作的?
在这一节中,我将提供该过程的高级概述。如果你不能完全理解,请继续看下面的章节。因为在接下来的部分中,我将用 python 代码实现所有这些想法。这样,就更清楚了。
让我们开始吧。假设我们的数据集看起来像这样:
这里,我们有五部电影、四个用户和两个特性。每个用户都为每部电影提供了一些反馈或评级。当然,每个用户并没有看完所有的电影。因此,有时评级是不可用的。
最后我们有两个特点:浪漫和动作。他们让你知道这部电影有多浪漫或者有多刺激。此评级介于 0 和 1 之间。0 浪漫意味着没有浪漫,1 浪漫意味着充满浪漫。
这个算法将被开发成使用用户评分的推荐系统。
如果一个用户看了很多电影,并对它们进行了评级,这个算法将最适合这个用户。
但是,如果某个用户没有提供任何评级,他或她将获得基于其他用户评级的推荐。
丢失的电影评分怎么办?
这是一个合理的问题。不是所有的用户都观看所有的电影,有时他们只是在观看后不对电影进行评级。所以,有很多缺失数据是正常的。在这种情况下,我们需要找到一种方法来填补那些缺失的数据。
线性回归法可以用来填补那些缺失的数据。提醒一下,下面是线性回归的公式:
Y = C + BX
我们在高中都学过这个直线方程。这里,Y 是因变量,B 是斜率,C 是截距。传统上,对于线性回归,相同的公式被写成:
这里,“h”是假设或预测值,X 是输入特征,θ0 和θ1 是系数。
如果您以前没有研究过线性回归,请先阅读这篇关于线性回归的文章:
学习线性回归的概念,并使用 python 从头开始开发一个完整的线性回归算法
towardsdatascience.com](/basic-linear-regression-algorithm-in-python-for-beginners-c519a808b5f8)
在这个推荐系统中,我们将使用同一部电影的其他评级作为输入 X,并预测缺失值。我们将避免偏差项θ0。
这里,θ1 在开始时随机初始化,并像线性回归算法一样通过迭代来细化。
如何细化 Theta1 的值?
与线性回归一样,我们将使用已知值来训练算法。以一部电影的已知收视率为例。然后使用上面的公式预测那些已知的评级。预测评级值后,将其与原始评级进行比较,以找出误差项。这是一个等级的误差。
同样,我们需要找出所有评级的误差。在此之前,我想介绍一下我将在整个教程中使用的符号,
这是总成本函数的公式,它将指示预测评级和原始评级之间的距离。
该公式的第一项表示误差项的平方。我们用正方形来避免任何负值。使用 1/2 来优化平方,我们计算误差项,其中 r(i,j) = 1。因为 r(i,j) =1 意味着用户提供了评级。
上述等式的第二项是正则化项。调整任何过拟合或欠拟合问题是有用的。
总成本函数?
如何知道一部电影是爱情片、喜剧片还是动作片?一直这样看完所有的电影,找出它的特点,真的会很费时间,很费钱。
所以,我们可以从用户的评分中得到启发。我们随机初始化θ值并通过迭代慢慢优化它的方式,我们可以对查找特征 x 做同样的事情。公式应该几乎类似于上面的成本函数。
在这两种情况下,都会有相同的误差项。我们可以添加θ和 x 的成本函数,如下所示:
梯度下降
梯度下降在每次迭代中更新θ和 X。以下是梯度下降的公式:
在这个公式中,α是学习率。在每次迭代中,θ和 X 值将被更新,并最终变得稳定。
电影推荐算法的实现
我将使用 Coursera 中的 Andrew Ngs 机器学习课程的数据集。他是把一个机器学习问题分解成碎片的最佳人选。请随意从该链接下载数据集并跟随:
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/rashida048/Recommender-System)
唯一的办法就是按照这个代码,边读边跑,如果你读这个是为了学习的话。
第一步:
导入必要的包和数据集。
import numpy as np
import pandas as pd
第一个数据集包含所有用户对所有电影的评级。
y = pd.read_excel('ex8_movies.xlsx', sheet_name = 'y', header=None)
y.head()
如果用户提供了评级,则下一个数据集包含 true,如果用户没有提供评级,则包含 False。
r = pd.read_excel('ex8_movies.xlsx', sheet_name='R', header=None)
r.head()
我们需要将这些布尔值转换成数值。我将用 1 代替 True,用 0 代替 False。
for i in range(len(r.columns)):
r[i] = r[i].replace({True: 1, False: 0})
该数据集中有特征 X:
X = pd.read_excel('movie_params.xlsx', sheet_name='X', header=None)
X.head()
θ值存储在这里,
theta = pd.read_excel('movie_params.xlsx', sheet_name='theta', header=None)
theta.head()
让我们检查数据集的形状。
输入:
y.shape
输出:
(1682, 943)
这意味着我们有 1682 部电影和 943 个用户。
输入:
X.shape
输出:
(1682, 10)
正如你所记得的,X 包含了特性。该数据集中有 10 个要素。
输入:
theta.shape
输出:
(943, 10)
输入:
r.shape
输出:
(1682, 943)
这是这个算法需要的所有数据集。x 和θ可以随机初始化。我们将在最后看到它。现在,我们将使用这个 X 和θ。
现在,我们将开发所有必要的功能。
成本函数
非常简单,我们将使用上面描述的总成本函数。它将 X,y,r,theta 和 Lambda 作为输入,并返回成本和梯度。
def costfunction(X, y, r, theta, Lambda):
predictions = np.dot(X, theta.T)
err = predictions-y
J = 1/2 * np.sum((err**2) * r)
reg_x = Lambda/2 * np.sum(np.sum(theta**2))
reg_theta = Lambda/2 * np.sum(np.sum(X**2))
grad = J + reg_x + reg_theta
return J, grad
梯度下降
在这个函数中,我们将使用上面讨论的梯度下降公式。它将 X,y,r,theta,Lambda,alpha 和迭代次数作为参数。我们将使用成本函数记录每次迭代的成本,并将返回更新后的 X、theta 和成本列表。
def gradientDescent(X, y, r, theta, Lambda, num_iter, alpha):
J_hist = []
for i in range(num_iter):
cost, grad = costfunction(X, y, r, theta, Lambda)
X = X - alpha*(np.dot(np.dot(X, theta.T) - y, theta) + Lambda*X)
theta = theta - alpha*(np.dot((np.dot(X, theta.T) - y).T, X) + Lambda*theta)
J_hist.append(cost)
return X, theta, J_hist
正常化
在此函数中,我们将对评级“y”进行标准化。首先,我们将计算每部电影的平均收视率。为此,我们将对每部电影的评分进行求和,然后除以该电影的“r”的总和。请记住,如果用户提供评级,则“r”数据集包含 1,如果用户未提供评级,则包含 0。
标准化 y 将是 y(如果用户提供了评级)减去平均值“y”的总和。
def normalizeRatings(y, r):
ymean = np.sum(y, axis=1)/np.sum(r, axis=1)
ynorm = np.sum(y, axis=1)*np.sum(r, axis=1) - ymean
return ymean, ynorm
所有的功能都是为了执行建议而开发的。现在,让我们使用这些函数。
给我推荐电影
为了给我推荐电影,我需要提供一些动作的评分。
my_ratings = np.zeros((1682,1))my_ratings[5] = 5
my_ratings[50] = 1
my_ratings[9] = 5
my_ratings[27]= 4
my_ratings[58] = 3
my_ratings[88]= 2
my_ratings[123]= 4
my_ratings[165] = 1
my_ratings[187]= 3
my_ratings[196] = 2
my_ratings[228]= 4
my_ratings[258] = 5
my_ratings[343] = 4
my_ratings[478] = 1
my_ratings[511]= 4
my_ratings[690] = 5
my_ratings[722]= 1
my_ratings[789]= 3
my_ratings[832] = 2
my_ratings[1029]= 4
my_ratings[1190] = 2
my_ratings[1245]= 5
我现在将在“y”数据框中添加我的评分。
y1 = np.hstack((my_ratings, y))
还需要添加“r”数据帧。这有点不同。因为“r”数据帧只显示我是否提供了电影的分级。然后,我将在索引中我的评级列表为 0 的地方放置 0,在我的评级列表有值的地方放置 1。
my_r = np.zeros((1682,1))
for i in range(len(r)):
if my_ratings[i] !=0:
my_r[i] = 1
现在,将这个 my_r 列表添加到“r”数据帧中,并将其命名为 r1。
r1 = np.hstack((my_r, r))
我们需要使用新的 y1 和 r1 找到一个归一化的 y 值。
ymean, ynorm = normalizeRatings(y1, r1)
你还记得吗,我在开始的时候说过,我们将在最后使用随机初始化的 X 和θ。
是时候了。我们试试用随机初始化的 theta 和 x 给我推荐电影吧。
num_users = y1.shape[1]
num_movies = y1.shape[0]
num_features = 10X1= np.random.randn(num_movies, num_features)
Theta1 = np.random.randn(num_users, num_features)
Lambda=10x_up, theta_up, J_hist = gradientDescent(X1, y1, r1, Theta1, 10, 500,0.001)
因此,我们得到了每次迭代的成本数据。我们来画一下。
import matplotlib.pyplot as plt
plt.figure()
plt.plot(J_hist)
plt.xlabel("Iteration")
plt.ylabel("$J(\Theta)$")
plt.title("Cost function using Gradient Descent")
看啊!经过几次迭代,代价函数变得稳定了!这意味着 X 和θ值在该点是稳定的。
推荐电影
使用我在开头提到的简单线性回归公式,我们来预测一下收视率。注意,我没有给所有的电影打分。因此,这里使用更新的参数,我们将预测所有用户的所有电影的评级。
p = np.dot(x_up, theta_up.T)
现在,当我使用 np.hstack 添加时,我的评分在第一列中。只分离我的评分,并使用上面的“normalizeRatings”函数中的“ymean”将其标准化。
my_predictions = p[:, 0] + ymean
my_predictions = pd.DataFrame(my_predictions)
现在,我将把这些评分添加到电影列表中。首先导入电影列表。
movies = open('movie_ids.txt', 'r').read().split("\n")[:-1]df = pd.DataFrame(np.hstack((my_predictions,np.array(movies)[:,np.newaxis])))
我们现在在一个数据框中并排显示电影列表和我的评分。如果我们只是对这个数据框架“我的评分”进行排序,我会找到最值得推荐的电影。根据我的评分,这里是我推荐的 10 部电影:
df.sort_values(by=[0],ascending=False,inplace=True)
df.head(10)
这些是根据我提供的评分推荐给我的电影。
结论
该算法使用用户的评级来工作。基于以前的购买记录、搜索记录或观看记录,可以开发一个类似的推荐系统。希望这对你有帮助。如果有任何问题,请不要犹豫在评论区提问。
您可以在这里找到本文的完整代码:
permalink dissolve GitHub 是超过 5000 万开发人员的家园,他们一起工作来托管和审查代码,管理…
github.com](https://github.com/rashida048/Recommender-System/blob/main/movie_recommendation1.ipynb)
更多阅读:
[## 使用 Python 的 Scikit-Learn 库的完整推荐系统算法:分步指南
一个简单、容易、有用的算法,只有几行代码
towardsdatascience.com](/a-complete-recommendation-system-algorithm-using-pythons-scikit-learn-library-step-by-step-guide-9d563c4db6b2) [## Python 中从头开始的完整异常检测算法:分步指南
基于概率的异常检测算法
towardsdatascience.com](/a-complete-anomaly-detection-algorithm-from-scratch-in-python-step-by-step-guide-e1daf870336e) [## Python 中从头开始的多项式回归
学习用一些简单的 python 代码从头开始实现多项式回归
towardsdatascience.com](/polynomial-regression-from-scratch-in-python-1f34a3a5f373) [## Python 中从头开始的完整逻辑回归算法:一步一步
使用真实世界的数据集开发算法
towardsdatascience.com](/a-complete-logistic-regression-algorithm-from-scratch-in-python-step-by-step-ce33eae7d703) [## 用 Python 从头开始构建神经网络
神经网络的详细说明和逐步实现
medium.com](https://medium.com/towards-artificial-intelligence/build-a-neural-network-from-scratch-in-python-f23848b5a7c6) [## Python 中用于检测心脏病的逻辑回归
发展逻辑回归演算法的重要方程式和如何发展逻辑回归演算法
towardsdatascience.com](/logistic-regression-in-python-to-detect-heart-disease-2892b138d0c0) [## 使用 Python 从零开始的多类分类算法:分步指南
本文介绍两种方法:梯度下降法和优化函数法
towardsdatascience.com](/multiclass-classification-algorithm-from-scratch-with-a-project-in-python-step-by-step-guide-485a83c79992) [## Python 中从头开始的完整 K 均值聚类算法:分步指南
还有,如何使用 K 均值聚类算法对图像进行降维
towardsdatascience.com](/a-complete-k-mean-clustering-algorithm-from-scratch-in-python-step-by-step-guide-1eb05cdcd461)
一个完整的带有亚马逊产品评论数据的 Python 情感分析算法:一步一步
Samuele Giglio 在 Unsplash 上拍摄的照片
使用 Python 的 Scikit_learn 库的 NLP 项目
在当今世界,情绪分析在任何行业都可以发挥至关重要的作用。使用自动化系统对推文、脸书评论或产品评论进行分类可以节省大量时间和金钱。同时出错的概率更低。在本文中,我将解释一个使用亚马逊产品评论数据集的情感分析任务。
我将使用 python 和一些 python 库。即使你以前没用过这些库,你也应该能很好地理解它。如果这对您来说是新的,请将每一步代码复制到您的笔记本上,并查看输出以便更好地理解。
使用的工具
- 计算机编程语言
- 熊猫图书馆
- sci kit-学习库
- 作为 IDE 的 Jupyter 笔记本。
数据集和任务概述
我将使用我前面提到的产品评论数据集。该数据集包含亚马逊婴儿产品评论。
如果你想用它练习,请从这个 链接 为自己下载数据集。
它有三列:名称、评论和评级。评论是文本数据,评级从 1 到 5,其中 1 是最差的评论,5 是最好的评论。
我们的工作是分析正面和负面的评论。让我们来看看数据集。这里我们使用前五个条目来检查数据。
import pandas as pd
products = pd.read_csv('amazon_baby.csv')
products.head()
作者图片
数据预处理
在现实生活中,数据科学家很少能获得非常干净并且已经为机器学习模型做好准备的数据。几乎每个项目,你都要花时间清理和处理数据。所以,让我们先清理数据集。
一个重要的数据清理过程是去除空值。让我们检查一下数据集中有多少空值。
在这个数据集中,我们必须处理这三列,这三列都很重要。如果数据在一列的任何一行中都不可用,则该行是不必要的。
len(products) - len(products.dropna())
我们在 1147 行中有空值。现在,检查一下我们总共有多少数据。
len(products)
我们总共有 183531 个数据。因此,如果我们删除所有的空值,我们仍然会有相当大的数据来训练算法。因此,让我们放弃空值。
products = products.dropna()
我们需要在 review 列中包含所有的字符串数据。如果有任何数据具有其他类型,将在后面的步骤中造成麻烦。
现在,我们将检查每一行的评审数据的数据类型。如果有任何一行的数据不是 string 类型的,我们将把它改为 string。
for i in range(0,len(products)-1):
if type(products.iloc[i]['review']) != str:
products.iloc[i]['review'] = str(products.iloc[i]['review'])
当我们进行情绪分析时,告诉我们的模型什么是积极情绪,什么是消极情绪是很重要的。
在我们的评级栏中,我们有从 1 到 5 的评级。我们可以定义 1 和 2 为差评,4 和 5 为好评。
3 呢?
3 在中间。不好也不坏。只是一般。但是我们要对好评和差评进行分类。所以,我决定去掉所有的 3。
这取决于雇主或你对好坏的看法。如果你认为你会把 3 放在好的评论位置,那就去做吧。但是我正在摆脱他们。
products = products[products['rating'] != 3]
我们将正面情绪记为 1,负面情绪记为 0。让我们写一个函数“情绪”,如果评分为 4 或更高,则返回 1,否则返回 0。然后,应用函数“情绪”并创建一个新列,将积极和消极情绪表示为 1 或 0。
def sentiment(n):
return 1 if n >= 4 else 0
products['sentiment'] = products['rating'].apply(sentiment)
products.head()
作者图片
看,我们现在在末尾增加了“情感”一栏!
首先,我们需要准备培训功能。将“姓名”和“评论”列合并为一列。首先,编写一个函数“combined_features”来合并这两列。然后,应用该函数并创建一个新列“all_features ”,它将包含来自 name 和 review 列的字符串。
def combined_features(row):
return row['name'] + ' '+ row['review']products['all_features'] = products.apply(combined_features, axis=1)
products.head()
作者图片
您可以在结尾处看到“所有功能”一栏。现在,我们准备开发情感分类器!
开发情感分类器
下面是一步一步的过程。
我们需要定义输入变量 X 和输出变量 y。
x 应该是“所有功能”列,y 应该是我们的“情感”列
X = products['all_features']
y = products['sentiment']
我们需要拆分数据集,以便有一个训练集和一个测试集。
scikit-learn 库中的“train_test_split”函数很有帮助。将使用训练数据集来训练该模型,并且可以使用测试数据集来测试该模型的性能。
“train_test_split”自动按 75/25 的比例分割数据。75%用于培训,25%用于测试。如果你想比例不同,你需要定义。
from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
我将使用 scikit-learn 库中的’计数矢量器。CountVectorizer 生成字符串中所有单词的向量。导入 CountVectorizer,并将我们的训练和测试数据放入其中。
from sklearn.feature_extraction.text import CountVectorizercv = CountVectorizer()
ctmTr = cv.fit_transform(X_train)
X_test_dtm = cv.transform(X_test)
让我们深入到最初的模型部分。这是最好玩的部分。我们将使用逻辑回归,因为这是一个二元分类。让我们进行必要的导入,并将我们的训练数据放入模型中。
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
model = LogisticRegression()
model.fit(ctmTr, y_train)
用训练数据训练逻辑回归模型。
结果
使用上面训练好的模型来预测测试数据的情绪。如果我们通过测试特征,它将预测输出 y,即情感数据。
y_pred_class = model.predict(X_test_dtm)
输出:
array([1, 1, 1, ..., 1, 1, 0], dtype=int64)
这是测试数据的输出。如你所知,我们用 1 表示好评,用 0 表示差评。
使用 accuracy_score 函数获得测试数据的 accuracy_score。因此,它会将预测的“情绪”与原始的“情绪”数据进行比较,以计算准确性的百分比。
accuracy_score(y_test, y_pred_class)
这个数据我在测试集上得到的准确率分数是 84%,非常好。
结论
这个简单的情感分析分类器在许多其他类型的数据集中也很有用。它也可以用于现实世界的项目和业务。我们在这里使用的数据集类似于真实的业务数据集。请在其他数据集上尝试这种技术。
更多阅读:
顶级大学高质量免费课程的链接
towardsdatascience.com](/great-quality-free-courses-to-learn-machine-learning-and-deep-learning-1029048fd0fc) [## 使用 Python 从零开始的多类分类算法:分步指南
本文介绍两种方法:梯度下降法和优化函数法
towardsdatascience.com](/multiclass-classification-algorithm-from-scratch-with-a-project-in-python-step-by-step-guide-485a83c79992) [## 完全理解精确度、召回率和 F 分数的概念
机器学习中如何处理倾斜数据集
towardsdatascience.com](/a-complete-understanding-of-precision-recall-and-f-score-concepts-23dc44defef6) [## 练习数据科学技能和制作优秀投资组合所需的所有数据集
一些有趣的数据集提升你的技能和投资组合
towardsdatascience.com](/all-the-datasets-you-need-to-practice-data-science-skills-and-make-a-great-portfolio-857a348883b5) [## Python Matplotlib 的日常备忘单
完整的可视化课程
towardsdatascience.com](/your-everyday-cheatsheet-for-pythons-matplotlib-c03345ca390d) [## 想在 12 周内成为数据科学家?
花钱前再想一想
towardsdatascience.com](/want-to-become-a-data-scientist-in-12-weeks-3926d8eacee2)
完全理解精确度、召回率和 F 分数的概念
机器学习中如何处理倾斜数据集
用倾斜的数据集开发有效的机器学习算法可能会很棘手。例如,数据集是关于银行欺诈活动或癌症检测的。你会在数据集中看到,99%的情况下没有欺诈活动,或者没有癌症。你可以很容易地作弊,只要一直预测 0(如果有癌症预测 1,如果没有癌症预测 0)就可以获得 99%的准确率。如果我们这样做,我们将有 99%准确的机器学习算法,但我们永远不会检测到癌症。如果某人患有癌症,她/他将永远得不到治疗。在银行里,不会有针对欺诈行为的行动。因此,对于这样一个有偏差的数据集来说,光靠准确性是无法决定算法是否有效的。
背景
有不同的评估矩阵可以帮助处理这些类型的数据集。这些评估指标被称为精确召回评估指标。
要了解精度和召回率,您需要理解下表及其所有术语。考虑二进制分类。它将返回 0 或 1。对于给定的训练数据,如果实际类为 1,预测类也为 1,则称为真正。如果实际类别为 0,而预测类别为 1,则这是一个假阳性。如果实际类别为 1,但预测类别为 0,则称为假阴性。如果实际类别和预测类别都是 0,则这是真否定。
利用这些,我们将计算精度和召回率。
精确
Precision 计算我们预测为欺诈的交易(预测类别 1)中有多少部分实际上是欺诈的。精度可以用下面的公式计算:
进一步分解,这个公式可以写成:
从公式中可以看出,精度越高越好。因为更高的精度意味着更多的真阳性。这意味着当我们说这笔交易是欺诈性的,这是真的。
回忆
回忆告诉我们,所有最初是欺诈性的交易中有多少部分被检测为欺诈性的。这意味着当一笔交易实际上是欺诈性的,如果我们告诉适当的银行当局采取行动。当我第一次读到精确和回忆的定义时,我花了一些时间才真正理解它们的区别。我希望你越来越快。如果没有,那也不用担心。你并不孤单。
召回率可通过以下公式计算:
用上面 2 x 2 表中定义的术语表示:
根据精确度和召回率做出决策
精确度和召回率让我们更好地了解算法实际上是如何工作的,尤其是当我们有一个高度倾斜的数据集时。如果我们一直预测 0,并且得到 99.5%的准确率,那么召回率和准确率都是 0。因为没有真正的阳性。所以,你知道分类器不是一个好的分类器。当精确度和召回率都很高时,这表明该算法做得非常好。
假设我们只在高度自信的情况下,想预测 y = 1。因为有些情况下它非常重要。尤其是当我们处理医疗数据时。假设我们正在检测某人是否患有心脏病或癌症。预测假阳性会给一个人的生活带来很多痛苦。提醒一下,一般来说,如果假设大于或等于 0.5,逻辑回归预测 1,如果假设小于 0.5,逻辑回归预测 0。
如果假设≥ 0.5,则预测 1
如果假设< 0.5,则预测为 0
但是,当我们处理上述一些敏感情况时,我们希望对我们的结果更加确定,如果假设≥ 0.7,我们预测 1,如果假设< 0.7,我们预测 0。如果你想对你的结果更有信心,你可以看到像 0.9 这样的值。所以你可以 90%确定某人是否患有癌症。
现在,看看精度和召回公式。真阳性和假阳性都会降低。所以,精度会更高。但另一方面,假阴性会更高,因为我们现在会预测更多的阴性。那样的话,召回会更高。但是太多的假阴性也不好。如果某人确实患有癌症,或者某个账户有欺诈活动,但我们告诉他们,他们没有癌症,或者该账户没有欺诈活动,这可能会导致灾难。
为了避免假阴性并获得更高的召回率,我们需要将阈值更改为如下所示:
如果假设≥ 0.3,预测 1
如果假设< 0.3,则预测为 0
与前一种情况相反,我们将有更高的召回率和更低的准确率。
那么门槛怎么定呢?这将取决于你的要求是什么。根据您的数据集,您必须决定是需要更高的精度还是更高的召回率。这是精确回忆曲线:
精确召回曲线可以是任何形状。所以,我在这里展示了三种不同的形状。如果您不能自己决定是否需要更高的精确度或更高的召回率,您可以使用 F1 分数。
F1 分数
F1 得分是准确率和召回率的平均值。但是平均的公式是不同的。常规的平均公式在这里不起作用。看平均公式:
(精度+召回)/ 2
即使精度是 0 或者召回率是 0,平均值仍然是 0.5。记住我们之前的讨论,精度为零是什么意思。我们总是可以预测 y = 1。因此,这是不可接受的。因为精确回忆的目的就是避免这种情况。F1 方程式的分数是:
这里,P 是精度,R 是召回率。如果精度为零或召回为零,F1 分数将为零。所以,你会知道分类器没有像我们想要的那样工作。当精确度和召回率都达到完美时,这意味着精确度是 1,召回率也是 1,F1 的分数也将是 1。所以,完美的 F1 分数是 1。尝试不同的阈值并计算精确度、召回率和 F1 分数,以找出您的机器学习算法的最佳阈值,这是一个好主意。
结论
在本文中,您了解了如何处理有偏差的数据集。如何使用 F1 分数在精确度和召回率之间做出选择?我希望它有帮助。
更多阅读
[## 使用 Python 从零开始的多类分类算法:分步指南
本文介绍两种方法:梯度下降法和优化函数法
towardsdatascience.com](/multiclass-classification-algorithm-from-scratch-with-a-project-in-python-step-by-step-guide-485a83c79992) [## 用 Python 从头开始构建神经网络
神经网络的详细说明和逐步实现
medium.com](https://medium.com/towards-artificial-intelligence/build-a-neural-network-from-scratch-in-python-f23848b5a7c6) [## Python 中用于检测心脏病的逻辑回归
发展逻辑回归演算法的重要方程式和如何发展逻辑回归演算法
towardsdatascience.com](/logistic-regression-in-python-to-detect-heart-disease-2892b138d0c0) [## 用几行代码在 Python 中搜索相似的文本:一个 NLP 项目
使用 Python 中的计数矢量器和最近邻法查找类似的维基百科简介,这是一个简单而有用的…
medium.com](https://medium.com/towards-artificial-intelligence/similar-texts-search-in-python-with-a-few-lines-of-code-an-nlp-project-9ace2861d261) [## 练习数据科学技能和制作优秀投资组合所需的所有数据集
一些有趣的数据集提升你的技能和投资组合
towardsdatascience.com](/all-the-datasets-you-need-to-practice-data-science-skills-and-make-a-great-portfolio-857a348883b5)
解决文本分类问题的初学者综合指南
利用文本分类方法分析 Twitter 数据中的错误信息
作者 尼基尔·乔希 和 纳拉辛哈·卡马特·阿迪—2020 年 6 月 26 日
简介
众所周知,对数据科学家的需求一直在稳步上升。我们辞去了一份高薪的咨询工作,去追求数据科学领域的职业生涯。当我们作为学生开始我们的旅程时,我们真的不知所措,不知道如何开始学习过程。作为一个不断发展的领域,互联网上有很多内容/平台。当已经有这么多可能的事情时,一个人自然会发现很难找到一个完美的开始,我们在第一季度的前两个月面临同样的问题。
当我们在网上寻找内容时,他们大多专注于机器学习算法,NLP 概念,一开始看起来超级令人兴奋。此外,当我们开始了解 Python 及其内置库的重要性时,我们对自己的职业选择非常着迷。然而,作为一个初学者,我们面临着如此多的困惑,我们将在这个博客中讨论。这篇文章是有意针对新手候选人的,我们将尝试详细说明应该注意的每一点,以便在这一流程中建立一个坚实的基础。
数据科学不是闹着玩的!
这是一个极具挑战性的领域,需要纯粹的统计学知识来理解基本概念。ML 看起来很吸引人,Python 也做对了你的大部分工作,那为什么还要学统计学呢?这是我们关于数据科学的第一个流言被终结的地方。我们遇到了各种旨在通过将大部分精力集中在构建模型上来解决问题的帖子/项目,并得出结论,它对给定的用例执行准确!!这是我们大多数人出错的地方。你还在迷茫吗,别急!请允许我们通过考虑一个经典的文本分类问题来阐述这一点;我们的第一个数据科学项目教会了我们很多在学习阶段从未预料到的事情。
预测全球疫情期间推特上的错误信息
啊!众所周知,Twitter 是数据科学项目的金矿。但是我们应该用 Twitter 做什么项目呢?当我们在 GitHub 上寻找几个项目来获得灵感时,我们发现大多数项目都倾向于情感分析。等等,我们要进行情感分析吗?选择一个项目主题是我们作为初学者面临的首要挑战。
提示 1:一开始就着手一个复杂的项目是绝对不行的。要脚踏实地!一步一步来!
像其他人一样,我们在开始时太受驱动了,想做一个复杂的项目。然而,我们意识到这不是正确的方法。我们想先搞清楚基本情况,经过几天的头脑风暴,我们敲定了几个有趣的话题。最后,我们决定对 twitter 上有关抗病毒药物、消毒剂和冠状病毒预防措施的错误信息进行分析。此外,选择这一主题的动机是为了理解实现解决方案背后的数学原理,以减少 Twitter 上的有害内容。
我们是如何解决这个问题的?
大多数像我们这样的新手在项目期间犯的主要错误是直接跳到项目要使用的 ML 算法的类型上!
提示 2:控制你的肾上腺素分泌!先看问题。请不要忽视数据工程部分。分析问题陈述,看看在你目前的知识水平下是否可行。
谢谢你走了这么远。从这里开始,我们将解释解决这个问题的逐步方法。
第一步:获取 TWITTER 开发者账户访问权限
为了使用 twitter 数据,我们需要一个 twitter 开发者帐户。这将为我们提供通过 TweePy 获取 tweets 的授权。但是,我们是如何创建 twitter 开发者账户的呢?
遵循以下步骤:
a.登录开发者账号,点击**“创建 app”**。
b.将出现一个弹出窗口。点击**‘应用’**并从下面的仪表板中选择相关选项。
c.填写所需的详细信息,并获取访问密钥和令牌
呜哇!!!第一步现已完成。获得访问权限后,请确保点击**“密钥和令牌”**选项卡,并复制所提供的令牌。它将进一步用于通过 TweePy 访问 REST API。
第二步:数据收集和存储
我们通过 TweePy 使用 REST API 抓取推文。在这篇文章中,我们假设我们所有的读者都已经有了很好的 Python 实践经验。如果没有,我们强烈建议访问任何免费的 Python 在线课程,让自己熟悉该语言的语法。
一旦从 Twitter 收到令牌和密钥并安装了 TweePy,就可以开始通过 Twitter API 提取数据了。您可以通过 Twitter 标准 API 搜索字段 找到不同的可用数据字段。
技巧 3:永远不要仅仅为了完成任务而写脚本。优化它以执行多个操作。下面的代码片段一次性完成了管道的获取和清理。编码是一门艺术!练习直到你做对为止!
首先,让我们导入所需的库:
**# Data extraction & exploratory analysis**
import tweepy
from textblob import TextBlob
from tweepy import OAuthHandler
import pandas as pd
import numpy as np
import re**#NLP**
from textblob import TextBlob
import nltk
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split
from nltk.stem import PorterStemmer
from nltk.stem import WordNetLemmatizer
nltk.download('punkt')
from nltk.corpus import words
nltk.download('stopwords')**#ML Libraries for text classification**
from sklearn.metrics import accuracy_score
from sklearn.naive_bayes import MultinomialNB
from sklearn.linear_model import LogisticRegression
一旦你的申请被批准,使用下面的脚本添加你自己的个性化 tokes。
**# Removed access keys and tokens for the sake of security**access_token = ''
access_token_secret = ''
consumer_key = ''
consumer_secret = ''
如前所述,现在是我们开始从 Twitter API 中提取数据的时候了。
**# authorize access to TweePy**auth = tweepy.OAuthHandler(consumer_key,consumer_secret)
auth.set_access_token(access_token,access_token_secret)
api = tweepy.API(auth,wait_on_rate_limit=True, wait_on_rate_limit_notify=True)**# Fetch tweets**tweets = []
sentiments =[]
count = 1
query = "#hydroxychloroquine OR #remdesivir OR #Remdesivir OR hydroxychloroquine OR remdesivir OR #GileadSciences OR GileadSciences OR #drug OR drug OR #antiviral OR antiviral OR #Antibiotic OR antibiotic"for tweet in tweepy.Cursor(api.search,q=query,count=450).items(50000):
print(count)
count+=1
try:
data = [tweet.created_at,tweet.id,tweet.text,tweet.source,tweet.retweet_count,tweet.user._json['screen_name'],tweet.user._json['created_at'],tweet.user._json['location'],tweet.coordinates,tweet.entities['urls']]
data = tuple(data)
tweets.append(data)
except tweepy.TweepError as e:
print(e.reason)
continue
try:
sentiment_data = [tweet.created_at,tweet.text]
sentiment_data = tuple(sentiment_data)
textWords=sentiment_data[1].split()
#clean tweets
cleanedTweet=' '.join(re.sub("(@[A-Za-z0-9]+)|([^0-9A-Za-z \t])|(\w+:\/\/\S+)|(RT)", " ", sentiment_data[1]).split())
analysis= TextBlob(cleanedTweet)
polarity = 'Positive'
if(analysis.sentiment.polarity < 0):
polarity = 'Negative'
if(0<=analysis.sentiment.polarity <=0.2):
polarity = 'Neutral'
#print (polarity)
dic={}
dic['Sentiment']=polarity
dic['Tweet']=cleanedTweet
dic['Polarity'] = analysis.sentiment.polarity
dic['Created_at'] = sentiment_data[0]
sentiments.append(dic)
except tweepy.TweepError as e:
print(e.reason)
continue
except StopIteration:
break
df_analysis = pd.DataFrame(tweets, columns = ['created_at','tweet_id','tweet_text','tweet_source','retweet_count','screen_name','account_creation_date','location','coordinates','urls'])df_analysis.to_csv('File Path')df_sentiment=pd.DataFrame(sentiments)df_sentiment.to_csv('File Path'
我们使用查询字符串来添加我们正在寻找的任何标签、关键字、关键短语或句柄(例如 query = " #羟氯喹" ),然后使用。items()功能。
在上面的脚本中, 文本 Blob 将我们的文本分类为阳性、阴性和中性标签(基于极性)。但是,我们为什么要使用 NLTK 呢?使用这两个库的唯一目的是理解每个包如何以自己的方式对文本处理做出贡献。此外,我们还强烈推荐浏览 SpaCy ,这是一个高级自然语言处理的开源软件库。
此外,我们可以设置自定义日期过滤器(since 和 until 参数)来查询给定日期范围内的 tweets。在执行此脚本之前,请确保添加您的文件路径来存储原始数据集和干净数据集。
tweepy.Cursor(api.search,q=query,since=2020-06-26 count=450).items(50000)
但是,请记住,Twitter 标准 API 搜索只能追溯到当前日期的 7 天之后。此外,计数参数指的是速率限制,请保持不变,即 450。
除了下载我们在上面实现的历史推文,我们还可以使用流 API 下载实时推文。请 查看Twitter 开发者手册了解更多信息。
第三步:分析并理解我们如何应用分类方法
文本分类是一个有监督的学习问题,它在机器学习和自然语言处理的帮助下将文本/标记分类到有组织的组中。 点击这里 了解更多详情。另外,情绪分析的基础知识可以在 这里找到 。
下面是我们的干净数据集后处理的快照:
df = pd.read_csv("text_analysis_antiviral.csv")
df.head()
清理数据集快照
如果您仔细观察数据集,会发现添加了 2 个新属性,其中包括情感和极性。它们说明了什么?好吧,我们假设你已经浏览了我上面附加的链接,这些链接有助于你理解分类方法的基础。
我们如何使用机器学习将这些文本分类为正面、负面和中性标签?在此之前,为什么我们甚至把他们排到上述标签?由于 TextBlob 已经按照极性对数据进行了分类,我们将使用它作为机器学习分类器的训练数据集。NLTK 在这里的工作是删除停用词并将句子分解成标记。然后,这些标记将经历词干化或词汇化的过程。
**# Perform text processing operations on the cleaned tweets**
def preprocess_tweet_text(tweet):
tweet.lower()
** # Remove urls**
tweet = re.sub(r"http\S+|www\S+|https\S+", '', tweet, flags=re.MULTILINE)
**# Remove stopwords**
stop = stopwords.words('english')
**#Tokenization**
tweet_tokens = word_tokenize(tweet)
filtered_words = [w for w in tweet_tokens if not w in stop]
**# Stemming**
ps = PorterStemmer()
stemmed_words = [ps.stem(w) for w in filtered_words]
**#Lemmatization**
lemmatizer = WordNetLemmatizer()
lemma_words = [lemmatizer.lemmatize(w, pos='a') for w in stemmed_words]
return " ".join(filtered_words)
提示 4:在阅读下面的内容之前,请仔细阅读上面的链接,以便对主题有一个清晰的了解。
这里的第一种方法是找到包含虚假声明/信息的推文,并将它们贴上负面标签。但是,TextBlob 不是已经这样做了吗?为什么要走这么远,还要用 ML 分类器?这是一种我们一开始就在谈论的自省。数据科学不仅仅是建模和准确性!它有很多方面,但不幸的是大多数时候都被低估了。
以“孙杀”为例。你认为这篇文章的标签应该是什么?TextBlob 会将其识别为中性,这是绝对正确的,因为它预测了这里的情绪。然而,我们的问题声明指出,错误信息应被视为负面标签。请不要混淆:)我们使用 TextBlob 来减少准备带有标签的训练数据集的负担。但是,TextBlob 可能无法正确识别标签。现在这完全没问题,因为我们都刚刚步入数据科学的世界!因此,随着我们的前进,我们可以创建自己的带有所需标签的训练数据,并针对各种用例进行测试!
步骤 4:让我们应用期待已久的 ML 分类器来训练数据集!
在应用模型之前,我们使用 TF-IDF 技术为提取的记号分配加权因子。下面的代码片段还将数据分为训练和测试。此外,我们的火车数据集中有大约 76000 条推文。
tf_vector = get_feature_vector(np.array(dataset_train.iloc[:, 0]).ravel())
X = tf_vector.transform(np.array(dataset_train.iloc[:, 0]).ravel())
y = np.array(dataset_train.iloc[:, 1]).ravel()
X_train = X
y_train = y
X_test = tf_vector.transform(np.array(dataset_test.iloc[:, 0]).ravel())
y_test = np.array(dataset_test.iloc[:, 1]).ravel()
你们不要担心!我们还将附上 GitHub 资源库的链接,该资源库将包含本项目中使用的所有 Python 笔记本。现在请把注意力集中在正确的概念上!
我们应该考虑应用哪种 ML 模型?我们使用流行的 朴素贝叶斯分类器 和 逻辑回归.) 进行分类。请点击 链接 了解这些型号之间的更多差异。
对 TextBlob 生成的数据集进行后训练,我们实现了 LR 模型 70%的准确率和 NB 模型 66%的准确率。
模特培训
第五步:测试时间到了!!
当我们将测试数据集输入 LR 模型时,我们发现了一些非常有趣的见解!!
根据 LR 模型测试数据集
哇哦。你们有没有看到《孙杀》已经被正确的认定为阴性了??在训练数据集时,除了 TextBlob 生成的数据之外,我们还包含了另外 300 个数据点!通过这种方式,它正确地将一些错误信息文本标记为负面的。不过,推文“我们喝漂白剂吧”还是中性的。有趣的是,我们训练过的模型错误标记了一些文本。这是我们作为数据科学家必须开始思考的地方。如前所述,我们刚刚开始我们的旅程。作为初学者完成这些步骤本身就是一项值得称赞的工作。因此,我们强烈建议正确理解这些概念。此外,一旦基础得到加强,高级思维的范围总是存在的!
如前所述,下面是GitHub 资源库链接 供大家参考!
谢谢大家!
如有任何问题或疑虑,您也可以发电子邮件给我们:
nikhiljoshi19@uchicago.edu&nkamathardi@uchicago.edu
参考
WhatsApp 群聊的综合数据分析
有没有想过你的哪个朋友发短信骂人最多?
在考虑我的下一个项目时,我的脑海中突然冒出了一个想法。为什么不对大学生的 WhatsApp 群聊进行数据分析,找出有趣的见解,如使用最多的表情符号,每个人的情绪得分,谁说的脏话最多,一天中最活跃的时间,或者该群体在大学教学时间使用手机吗?这些肯定会是一些有趣的见解,对我来说比对你更有意义,因为这次聊天的人是我个人认识的人。
注意:我用两个字母代表我的每个朋友,这是他们名字的缩写,以保持匿名。
数据检索和预处理
第一步是收集数据。WhatsApp 允许你通过. txt 格式导出聊天内容。打开这个文件,您会得到如下格式的消息:
说假话?不,爸爸!
由于 WhatsApp 的文本是多行的,你不能一行一行地阅读文件,然后得到你想要的每条信息。相反,您需要一种方法来识别一行是新消息还是旧消息的一部分。您可以使用正则表达式来实现这一点,但是我使用了一个更简单方法。我创建了一个名为 vali_date()的函数,如果传递的参数是有效的日期,它将返回 True。
我对自己如何命名这个函数感到非常自豪。
在读取每一行时,我根据逗号将其拆分,并获取 split()函数返回的第一项。如果该行是新消息,第一项将是有效日期,它将作为新消息附加到消息列表中。如果不是,则该消息是前一条消息的一部分,因此将作为一条连续消息附加到前一条消息的末尾。
从这里开始,只需要从每一行中提取必要的细节:发送日期、发送时间、发送者和消息本身。这只是使用一些简单的字符串处理函数,主要是 split(),然后用它制作一个数据帧。如果您使用相同的方法,请确保正确指定日期和时间格式。
该导出还包含人员何时被移除、人员何时被提升为管理员以及其他对我们没有用处的功能性消息。用我写的代码,这些消息被设置为带有空白消息的发送者姓名。为了过滤掉这些关键字,我使用了一个非常简单的函数来检查发件人的姓名是否包含这些关键字。为了说明没有硬编码到 if 条件中的其他消息,我检查了发件人姓名的字数。在我使用的导出中,我没有一个人的名字超过 3 个单词,但是如果你在做这样的事情,你必须考虑不同的名字。我还删除了一个朋友的旧号码,它不能通过上面的 if 条件,所以我必须用另一个条件来解释。如果你想避免这个痛苦的过程,你应该使用正则表达式,我很尴尬的没有这样做。
由于我以单一的 DateTime 格式加载了日期和时间,因此我可以轻松地从中提取特定的信息,比如发送日期或月份,这对热图很有用。
此时,我想我已经准备好开始分析了,所以我绘制了一个简单的线图来查看这些年来消息的频率。这个群是 2017 年最后一个季度创建的,聊天是 2020 年导出的。我希望看到一个漂亮的线图,在奇怪的地方有波峰和波谷。但是当我看剧情的时候,我看到了一些奇怪的东西。
请注意,导出的前半部分没有消息。这似乎很奇怪。起初,我以为是我的文本处理出了问题,但我最终发现,WhatsApp 聊天导出是有限制的,它们可以导出多少条消息。这个限制大约是 40,000,这解释了为什么导出的前半部分没有很多消息。观察数据帧的形状,它有 39,489 行。在这一点上,我感到失望的是,我几乎一半的数据都无法访问。
但是等等!
隧道尽头的光来了。我的朋友也在这个小组中,他提到他可以使用他的旧手机。他把旧手机里的聊天记录导出来,发了过去。我应用了与第一次导出时相同的提取技术,尽管由于不同的日期表示和不同的联系人姓名,我对代码做了一些小的修改,但这次新的导出有令人惊讶的 68,584 条消息(我不确定它怎么会超过 40,000 条)。我合并了这两个数据帧,删除了重复的,最终得到了总计 74,357 条消息,时间跨度超过 2.5 年。线图现在看起来好多了。
探索性数据分析
现在我们有了一个干净的数据框架,是时候对它进行分析了。首先,由于几乎所有的情节都是将一个人与另一个人进行比较,我将为每个人指定一种特定的颜色,这样就可以很容易地在多个情节中识别每个人。我从这个网站上选择了我的调色板。
接下来,我制作了一个字典,其中每个键都是名称,每个键的值都是分配给它们的颜色。我创建了一个函数,它给定一个名称列表,对颜色进行重新排序,以匹配绘图的顺序。这个函数将有序的名称作为输入,并返回一个重新排序的颜色列表。这个列表必须被传递到 seaborn 绘图函数的pallete
参数中。
现在我们为每个人准备了一套很好的颜色,我们可以用触须来可视化。
我的第一个图是每个人发送的消息总数。为此,一个简单的 seaborn countplot 就足够了。下一个是每个人的平均消息长度。为此,我创建了一个名为msg_length
的新列,它包含每条消息的长度,这是我通过使用 lambda 函数得到的,该函数返回给定消息的长度。我只是按名称对数据帧进行分组,然后对返回的 groupby 对象应用mean()
。
看到这样的剧情并排真的很有意思。例如,发短信最少的人,MM,平均打出了第二长的信息。这意味着这个人不会发送很多 WhatsApp 消息,但如果他们发送了,也很长。我们可以看到 BA 发送的消息最多,但消息长度相对较长。RF 似乎在平均消息长度上击败了所有人,但仔细观察,这是由于一些“异常值”,如下所示:
有人真的很执着。
由于这里没有关于什么是真正的消息的规则,我将把这些消息放在里面,不把它当作离群值。 WhatsApp 是野生的。
导出的聊天在导出时没有任何媒体文件。任何包含媒体的消息都用“”表示。我们可以用这个过滤掉,看看谁发的媒体最多。
巴遥遥领先于所有人。他在总消息数上排名第一,在平均消息长度上排名第三。最具奉献精神的贡献者奖授予 BA!
不是说它值多少钱。
时间
接下来我们可以检查从每条消息的日期时间戳中提取的月份。我们可以使用这些来制作热图,以检查最活跃的时间段。我会把两块地并排放在一起。
我按月份对数据帧进行分组,并对返回的对象应用 sum 函数。为了统计 groupby 的每个组中的消息数量,我已经创建了一个名为count
的列,其中每条消息的编号为 1。因为月份是有序的,所以我传递了一个包含月份的字符串列表,以便传递给绘图函数的order
参数。
我们可以看到,一年中的最后 3 个月比其他月份活跃得多。最活跃的日子是 11 月的星期五和 12 月的星期一,然而,我们不能从中推断出太多。这可能是由于某些日子,而不是重复模式。为了证明这一点,我们可以检查最活跃的日期,看看它们是在一周的哪几天。
最高的两天是在 11 月和 12 月,这导致了这几个月的高平均值。
为了清楚地了解不同日期的活动,我们通过汇总一周 7 天中每一天的消息计数来绘制一个单独的图。为了更进一步,我们可以查看一天中每个小时的聚合。
看起来除了星期六之外,这一天本身没有什么变化。这可能是因为周六是周五后的第一个周末,人们通常会休息并做其他活动,而不是在手机上发消息。
观察每小时的活动,我们可以看到大多数的群体活动发生在晚上。一些其他有趣的事情发生了:
- 从上午 9 点到 10 点的秋天。上午 9 点是开始上课的时间,没有多少学生倾向于在这个时间使用手机,因为他们要么赶去上课,要么和朋友聊天。
- 下午 1 点的小高峰。这是在大学的午餐时间,因为下课了,人们更倾向于使用手机。然而,从上午 11 点到 12 点只有轻微的增加,这一事实表明我们在教学时间积极参与小组活动。用数据证明这种行为并不令人惊讶,但仍然令人着迷。
- 从下午 3 点跳到下午 4 点。这是因为群里每个人都是大学生。大学在下午 3:30 结束,我们所有人都开始回家——在此期间,我们要么在回家的路上睡在公交车上,要么忙于做其他事情。
表情符号
使用 Python 的emoji
库,我们能够从短信中提取表情符号。
对于小组中的每个人,我将创建一个字典,其中包含作为关键字的表情符号和作为其值的出现次数。我试图让字典包含至少出现 1 次的表情符号,但我的代码中有些东西不起作用,所以我为小组中每个人的每个可用表情符号初始化了计数 0。效率低下,我知道,但很有效。
我遍历数据帧中的每一行,对于每条消息,我用消息中的表情符号索引字典,并将计数加 1。然后我把字典按降序排序,得到每个人最常用的表情符号。
还绘制了一个柱状图,给出了每个人的表情符号总数。
我们可以看到,最常见的表情符号是哭笑表情符号,这与 Unicode 协会的报告一致,该报告称😂是最常用的表情符号。
有一些表情符号不是由 Google Colab 提供的。这些可能是较新的表情符号。RF 似乎使用最多的表情符号,尤其是👍表情符号,有点可疑。我们可以看到,这是由于单一的信息,而不是他们的集体短信习惯。
脏话&情感
一些真正令人兴奋的事情!有一个名为profanity_check
的库可以检查给定的消息是否包含脏话。我想知道脏话对信息的情绪有多大影响。
首先,我创建了一个新列,如果消息包含脏话,则包含 1,如果不包含,则包含 0。这是使用前面提到的库中的predict
函数来完成的。然后,我们可以按姓名对数据帧进行分组,并获得骂人列的平均值,这就给出了每个人在邮件中含有脏话的百分比。
我们可以看到 BA,RF 和 GJ 说脏话最多。因为事实证明他从来没有做出多大贡献。其他人则介于两者之间。
现在,为了测试脏话是否会影响情绪,我需要找到每条信息的情绪。为此,我将使用两个不同的分析器:NTLK 的 VADER(价感知词典和情感推理器)和 TextBlob。首先是 VADER。polarity_scores
函数返回一个字典,其中有许多关键字,如正面情绪、负面情绪和整体/复合情绪。我将在这里使用复合情绪,它可以给出范围从-1 到+1 的值,前者表示最消极,后者表示最积极。从 TextBlob 库中,TextBlob
函数返回一个情感,该情感被分类为两极性和主观性。这里,我们将再次使用范围从-1 到+1 的极性。
对于 VADER 来说,因为我们取情感的平均值,所以条平均在零左右,因为在有情感的文本中有许多中性文本。我们可以看到,骂人最多的巴,平均情绪最消极。RF 和 GJ 是第二和最渴望骂人的用户,然而,GJ 的负面情绪比 RF 多,这表明单单脏话并不能决定信息的负面情绪。VADER 对社交媒体上表达的情绪特别敏感,因为 WhatsApp 是一款社交媒体应用,我们可以相信这些情绪在某种程度上是准确的。
有趣的是,除了、巴和得分最低的前两名,TextBlob 对所有人进行了完全不同的情感排名。尽管 VADER 将 3 个人归类为平均负面情绪,但 TextBlob 返回的平均情绪都是正面的。
为了更深入地了解哪一个更准确,我们可以查看根据 VADER 和 TextBlob 的极性得分排序的消息,并直观地检查这些消息,以查看给出的情绪是否有意义。
第一条消息看起来很有趣。让我们仔细看看。
这是一个带有大量心形表情符号的表情符号,VADER 将其归类为具有最高积极情绪的表情符号,这是理所当然的。邮件的长度可能是造成这种情况的原因之一。然而,TextBlob 似乎只给了它一点积极的情绪。
上面列表中的第五条消息是一家公司的促销活动:
嗨,来自的问候。这是关于那些参加过我们项目的人的新会员计划。我们正在为我们的公司寻找“学生大使”。如果你有兴趣,请通过 WhatsApp 或致电@*对了,谁是学生大使?*他/她将在各自的机构中代表。*他/她的职责是什么?*代表在其机构内组织研讨会/竞赛/速成班/客座讲座。*作为大使,你得到了什么?*您可以免费参加我们的所有项目/活动。如果发现你有才华,你将被录用为实习生。最重要的是对你的研究或项目工作的支持和指导。在你完成学业后,你将继续成为团队的一员。
这一信息显然没有积极的基调,但 VADER 却给了它很高的极性分数。
让我们看看按 TextBlob 极性得分降序排序的消息。
看起来 TextBlob 更适合短消息,因为它对短消息的积极情绪评分为 1.0。在所有邮件中,有 251 封邮件的正面情绪得分为 1.0。
总的来说,我认为我更喜欢 VADER 的观点,因为它似乎更适合长消息,并且特别适合社交媒体上表达的观点。
结论
那很有趣!看到人们的短信习惯和日常生活中的事件反映在文本中真的很有趣。我建议你看看我的代码,并将其应用到你自己的群聊中。然而,必须在数据帧创建部分进行一些修改。如果你有兴趣,给我发消息,我会帮你分类。
感谢您的阅读!让我知道你对这篇文章的看法。
密码
激活功能综合指南
对数据科学的许多曲线进行现代考察
自 2012 年以来,神经网络研究的进展主导了大多数人工智能(AI)文献,模型迅速接管了各种主题的基准。在这些创新的核心,激活函数在神经网络的效率和稳定性方面起着至关重要的作用。在这篇文章中,激活功能研究的最新发展水平将尽可能简要地概述,并清晰、实际地关注它们为什么被发明以及何时应该被应用。
paweczerwi ski 在 Unsplash 上的照片
目录
- 为什么激活功能? :
-强制非线性
-强制特殊数字属性 - 雷鲁家族
——整流器: 雷鲁、 LeakyReLU 和 PReLU ——指数运算: ELU 和SELU ——非单调运算: 嗖嗖和塞鲁 - 特殊族
- 线性 : 需要原始输出或融合运算时会用到 -Tanh**:归一化回归+L1/L2 -Sigmoid:二元分类+二元交叉熵。 -soft max😗*范畴分类+范畴交叉熵 - 关闭
为什么要激活函数?
简而言之,激活函数解决了神经网络中的两个关键问题:
- 确保激活图是非线性的,因此是相互独立的;和
- 确保某些输出具有基本的数字属性,例如,在[-1,1]范围内或者是有效的概率分布。
非线性
为了理解非线性激活图的需要,考虑下面两个函数: f(x) = ax + b 和 g(x) = (c+d)x + (e + f) 。前者只有两个常数,而后者有四个。问题是:它们实际上是两种不同的功能吗?
答案是否定的,“*(c+d)”*和“*a”*的表现力是一样的。如果你选择 c = 10 和 d = 2 ,我可以选择 a = 12,我们会得到相同的结果。“(e + f)”和“b”也是如此。为了有效地拥有四个独立参数,它们必须不能组合。在数学术语中,这意味着参数之间的关系必须是非线性的。例如, h(x) = sin(cx + d) + fx + e 是一个有四个参数的非线性模型。
在神经网络中,如果层是线性的,两个连续的层将是可组合的。因此,它们实际上只是一层伪装。为了不是线性的,所有层都被传递到非线性函数中,例如 ReLU 和 Tanh 函数,将它们隔离到单独的功能单元中。
数字属性
当回答“是”或“否”的问题时,例如“图像中是否有人脸”,false 被建模为 0,true 被建模为 1。给定一个图像,如果网络输出是 0.88,我们说网络回答为真,因为 0.88 更接近于 1 而不是 0。然而,网络的输出可以是 2 或-7。怎么能保证它的答案会在[0,1]范围内呢?
为此,设计了几个激活函数来保证某些数值特性。对于二进制分类情况, sigmoid 函数( σ(x) )接受范围[-∞,∞]内的输入,并输出范围[0,1]内的值。同样,双曲正切函数( tanh(x) )将[-∞,∞]映射到[-1,1]。对于独热编码的分类数据, softmax 函数将所有值压缩到[0,1]区间,并确保它们的总和为 1。
通常,这些“数字属性”激活用于网络的最后一层,称为输出层,因为这通常是唯一需要特殊处理的层。对于所有其它的,使用更简单的非线性,例如 ReLU 族。虽然存在网络中间需要特殊激活的情况,例如在对象检测模型和注意层上使用的情况,但这些并不是标准情况,不在本文的讨论范围之内。
雷鲁家族
在上一节中,我们看到了为什么需要激活以及激活可以解决哪些问题。此外,我们注意到所有层都要求激活功能独立,但只有少数层需要特殊功能。对于所有普通层,通常使用 ReLU 系列的激活。
在进入肮脏的细节之前,我想强调的是,在 ReLU 类激活的领域中,使用其中一个而不是另一个并没有太多特定问题的理由。实际上,人们只是在一个循环中尝试十几个时期,看看哪个在他们的任务中表现最好。
也就是说,一个经验法则是在开发期间尽可能长时间地坚持原始的 ReLU 激活,如果您的模型表现不佳,请按照 Tensorflow 2 文档中给出的建议跳到 SELU 激活(即使对于 PyTorch 用户也是如此),并取消所有的批处理规范化。我知道这听起来有点刺耳,但它确实有效,可能会给你带来 5%到 10%的提升。
作为总结,下图总结了 ReLU 系列中最著名的激活,以及它们的图(左)和它们在 CIFAR-10 数据集上的性能(右)。
图 ReLU 系列中最广为人知的函数(左)及其在 CIFAR10 数据集上 200 个时期内各自的性能图(无遗漏)。摘自:缩放的指数正则化线性单元(SERLUs)的有效性
整流器线性单元(ReLU)
整流器的数学定义是:
ReLU(x) = max(0,x)
在英文中,如果是正数,返回 x ,如果是负数,返回 0。
这是可能的最简单的非线性之一;计算最大值函数非常简单。ReLU 函数的早期用途之一来自于 AlexNet 架构,它使用这种激活方式的训练速度几乎是更传统的 Tanh 函数的八倍。出于这个原因,直到今天,ReLU 系列激活是大多数层的事实上的选择,因为它们计算简单,但有效。双赢的局面。
此外,早期的神经网络被一个称为爆炸/消失梯度的问题所困扰。总之,在反向传播过程中,当您移回网络时,梯度会彼此相乘,因此具有大梯度的大梯度会使信号爆炸,而具有近零梯度的近零梯度会使信号消失。使用 ReLU 激活,只有两种可能的梯度:一是正部分,零是负部分。因此,关于激活函数在该问题上的作用,整流器有效地解决了爆炸问题,这可能是最糟糕的,同时产生了死梯度问题。
泄漏单元
大多数人第一次看到 ReLU 函数时提出的第一个顾虑是:负的部分真的被扔掉了吗?是的,它是。研究人员对此感到困惑,提出了 LeakyReLU。不要扔掉消极的部分,而是返回一个减少的版本。数学上:
LeakyReLU(x) = max(0,x) + min(0.01⋅ x,0)
这样,信号不会完全丢失,但会因泄漏因子而显著减弱。在实践中,这在某些情况下证明是有效的。此外,它还缓解了死梯度问题,允许至少一部分信号通过。在接下来的激活中,玩消极的部分是一个反复出现的主题。
下一次迭代是参数 ReLU,简称 PReLU。基本原理是:为什么是 0.01?相反,让我们引入一个α变量,让它是可训练的。这样,我们不需要自己定义泄漏系数;我们让网络自己学习最合适的值。在表达形式上:
PReLU(x) = max(0,x) + min(αx,0)
请记住,α变量不是全局变量。每个单位都有它的可训练α。这种激活展示了数据科学的思维方式:如果可以让模型决定什么是最好的,为什么要自己设置呢?
指数单位
继续追求更好的激活性能,2015 年底在产生了对负部分使用指数函数的想法。指数函数对于负值是饱和的,这意味着它平滑地趋向于一个固定常数。使用它,我们可以更接近地模拟原始的 ReLU 函数,它在零处饱和,同时仍然在某种程度上保留负的部分。这是它的数学公式:
ELU(x) = max(0,x) + min(eˣ — 1,0)
在许多情况下,ELU 函数是对原始 ReLU 函数的明显改进。相比之下,漏变量并不总是更好。
该领域的最新进展之一被称为缩放指数线性单元,或 SELU,其主要创新是自规范化。这意味着,当训练时,它将向输出零均值和单位方差的结果收敛。实际上,这使得批量规范化层变得过时。因此,使用 SELU 激活的模型更简单,需要的操作更少。最后,通过用神奇的常数简单地缩放正负部分,就可以实现自规范化属性。形式上:
⋅最大值(0,x)+1.7580⋅min(eˣ-1,0)卢瑟(x)≈1.0507
有关使用该激活函数和推导神奇常数的更多详细信息,请考虑阅读论文和张量流文档。上面提到的常数是通过把原来的 SELU 表达式简化成更紧凑的形式而得到的。
非单调激活
到目前为止,ReLU 家族的所有激活都是单调递增的。在英语中,这意味着函数值只会增长。标志性的非单调函数有抛物线( x )和正弦函数( sin(x) ),抛物线上下周期性变化。
非单调激活的第一个成功提案是谷歌大脑团队的 Swish 函数,它被简单地定义为:
F(x) = x ⋅ σ(x)
σ(x)是 sigmoid 函数。虽然该表达式与 ReLU 函数不相似,但它们的图非常相似,正部分接近相同,负部分在零处饱和,负部分在零附近出现“凹陷”或“腹部”(图 1,蓝色)。这是通过“自门控机制实现的。基本上, x 是“信号”, σ(x) 是“选通函数”(在零点饱和的函数),将 σ 应用于 x 并乘以 x 就是取信号并自己选通,这样,一个自选通操作。在团队实验中,他们发现对于非常深的网络(30+层),这种激活优于 ReLU 功能。
最后, SERLU 激活是对 SELU 函数的改进,保留了自归一化属性,同时包括一个自门控机制,以便在负值时在零处饱和。作者通过使用指数函数作为门控操作,而不是 sigmoid,并重新计算魔法常数来实现这一点。这导致函数的负端出现一个大的“下降”,类似于 Swish 函数,但更明显(图 1,红色部分)。形式上,SERLU 被定义为:
塞卢(x) ≈ 1.0786 ⋅最大值(0,x) + 3.1326 ⋅ min(x⋅ eˣ — 1,0)
注意 x ⋅ eˣ 和 x ⋅ σ(x) 之间的相似性。两者都是自门控机制。
截至 2020 年,现在判断这些非单调函数是否能够经受住时间的考验,并取代 ReLU 或 SELU 成为一个良好的通用替代方案还为时过早。然而,如果可以的话,我敢打赌,自规范化特性将会一直存在。
特殊家庭
如前所述,有些层需要特殊处理,超出了 ReLU 类激活所能提供的范围。对于这些层,使用线性、sigmoid、tanh 和 softmax 激活,其用例如下:
- 线性:当你需要网络的原始输出时使用。这对于融合运算很有用,例如 sigmoid-crossentropy 和 softmax-crossentropy ,它们在数值上更稳定,并且用于非标准化回归。此外,在理论分析中,这种激活对于调试和简化是有用的。
- Tanh :用于归一化回归问题,其输出在[-1,1]范围内。通常与 L2 损失一起使用。
- Sigmoid :见于二进制分类问题将输出压缩到[0,1]范围。几乎总是与二元交叉熵损失一起使用。
- Softmax :在范畴分类上下文中看到,以强制网络输出是有效的概率分布。这意味着所有值都在[0,1]范围内,并且总和为 1。与分类交叉熵损失一起使用。
如您所见,给定一个问题,选择您应该使用哪个激活是很简单的。此外,所选函数提示了应该使用/考虑哪些损失函数。虽然这是一种简化,但作为一个起点是有用的。如前所述,一个经验法则是始终使用 ReLU 激活,为最后一层选择最合适的特殊函数,并在以后的迭代中,扩展这些初始选择并尝试替代公式。
最后,值得一提的是,对于某些问题,类并不是互斥的。在这种特殊情况下,单个输入可能会被标记为多个类。在这些情况下,每个类使用 sigmoid,而不是 softmax 激活。通过这种方式,所有输出都被压缩到[0,1]范围内,但不会强制累加到 1。
关闭
在这篇文章中,国家的最先进的激活功能进行了审查,与实际指导,使用和为什么。总之,激活用于使网络非线性化,并对输出图层实施特殊属性。对于内部层,使用 ReLU 系列,并且作为一个经验法则,尽可能长时间地坚持 ReLU 激活,然后切换到 SELU 激活,并移除所有批处理规范化操作。对于输出图层,考虑对非标准化/标准化回归使用线性/双曲正切激活,对二元/分类使用 sigmoid/softmax。
正如在任何指南中一样,总会缺少一些东西。在这里,我故意跳过了不太为人所知/使用过的选项,比如 softplus 、 softsign 和 relu6 函数。我选择这样做是为了让文章尽可能简短,而不影响流行的文章。如果您错过了正在讨论的任何激活功能,不同意某些东西或希望看到一些概念的扩展,请在评论部分让我知道,我将尽我所能保持这份文件的最新:)
如果您对本文有任何问题,请随时发表评论或与我联系。如果你刚接触媒体,我强烈推荐订阅。对于数据和 IT 专业人士来说,中型文章是 StackOverflow 的完美搭档,对于新手来说更是如此。注册时请考虑使用我的会员链接。
感谢阅读:)
用 Python 下载股票价格的综合指南
来源: Unsplash
下载历史股票价格,只有一行代码!
这篇短文的目的是展示用 Python 下载股票价格(和股票相关的数据)是多么容易。在本文中,我介绍了两种方法,都使用 Yahoo Finance 作为数据源。有许多替代产品(Quandl、Intrinion、AlphaVantage、Tiingo、IEX 云等)。),然而,雅虎财经可以被认为是最受欢迎的,因为它是最容易访问的(免费且无需注册)。
第一种方法使用一个名为yfinance
的库,这绝对是我所知道的最简单的方法。第二个是yahoofinancials
,稍微复杂一点,但是,由于我们在下载数据方面付出了额外的努力,我们收到了更多与股票相关的数据。
让我们开始吧!
设置
我们需要加载以下库:
import pandas as pd
import yfinance as yf
from yahoofinancials import YahooFinancials
你可以pip install
你错过的图书馆:)
使用 yfinance 下载股票价格
yfinance
是一个非常方便的库,是我下载股票价格的必去库。它以前被称为fix_yahoo_finance
。这个库的简短历史是作为对流行的pandas_datareader
库的修复而开始的。随着时间的推移,Yahoo Finance 改变了 API,相关的功能被弃用。这时候fix_yahoo_finance
被引入,再次使从雅虎财经下载数据成为可能。它既是pandas_datareader
的补丁,也是一个独立的库。
事不宜迟,下面我展示如何快速下载特斯拉的股票价格:
运行代码会产生下表:
默认情况下,该函数下载每日数据,但是我们可以将interval
指定为以下之一:1m、5m、15m、30m、60m、1h、1d、1wk、1mo 等等。下载数据的命令可以简化为一行:
tsla_df = yf.download('TSLA')
然而,我想展示如何使用函数的参数。我提供了所考虑的时间范围的开始和结束日期,并禁用了进度条(对于如此少量的数据,显示它没有意义)。我们可以通过提供一个列表(比如[‘TSLA', ‘FB', ‘MSFT']
)作为tickers
参数,一次性下载多种资产的股票价格。此外,我们可以设置auto_adjust = True
,这样所有显示的价格都会针对潜在的公司行为进行调整,比如拆分。
除了yf.download
函数,我们还可以使用Ticker()
模块。下面我给出一个下载特斯拉股票价格全部历史的简短例子:
运行代码会生成以下图形:
使用Ticker
模块的好处是我们可以利用连接到它的多种方法。我们可以使用的方法包括:
info
—打印出一个 JSON,其中包含许多有趣的信息,比如公司的全名、业务摘要、所处的行业、上市的交易所(还有国家、时区)等等。同样值得一提的是,JSON 包括一些财务指标,如 beta 系数。recommendations
—包含分析师提出的建议的历史列表actions
—显示股息和拆分等操作major_holders
—顾名思义,显示主要持有人institutional_holders
—显示机构持有人,如下图所示:
calendar
—显示传入事件,如收益。我写了一篇关于从雅虎下载完整收益日历的最简单方法的文章。金融。
有关可用方法的更多信息,请务必查看yfinance
的 GitHub 资源库。
使用 yahoofinancials 下载股价
本文中我想提到的第二个库是yahoofinancials
。虽然我发现使用这个库要求有点高,但是它提供了很多在yfinance
中没有的信息。让我们从下载特斯拉的历史股价开始:
我们首先通过传递 Tesla 的 ticker 实例化了一个YahooFinancials
类的对象。这样做了之后,我们就可以用各种方法提取有用的信息。我们从历史股票价格开始。这个方法的用法是不言自明的。需要注意的一点是,结果是一个 JSON。这就是为什么我必须运行一系列操作来提取相关信息并将 JSON 转换成一个pandas
数据帧。运行该代码片段会导致:
获得历史股票价格的过程比yfinance
的情况要长一点。现在是时候展示yahoofinancials
的光芒了。我简要描述一下最重要的方法:
get_stock_quote_type_data
—返回股票的大量一般信息,类似于yfinance
的info
。使用方法返回以下内容:
get_key_statistics_data
/get_summary_data
—这两种方法返回许多统计数据(如 beta、市净率等。)get_stock_earnings_data
—返回收益信息(年度和季度)以及公司将报告收益的下一个日期:
这种形式的 JSON 可能不是最易读的,但是它适合屏幕:)
get_financial_stmts
—获取公司财务报表信息的有用方法
我展示了一个使用这个库下载单个公司信息的例子。然而,我们可以很容易地提供一个公司列表,这些方法将返回适当的 JSONs,其中包含每个公司所请求的信息。让我们看一个下载多家公司调整后收盘价的示例:
将数据放入pandas
DataFrame 需要多一点的努力,然而,代码可以很容易地重用(对于YahooFinancials
类的不同方法也有轻微的修改)。
结论
在本文中,我展示了如何轻松地从 Yahoo Finance 下载历史股票价格。我从使用yfinance
库的一行程序开始,然后逐渐深入提取更多关于股票(和公司)的信息。使用上面提到的库,我们可以在雅虎财经网站上下载几乎所有可用的信息。
您可以在我的 GitHub 上找到本文使用的代码。一如既往,我们欢迎任何建设性的反馈。你可以在推特或评论中联系我。
喜欢这篇文章吗?成为一个媒介成员,通过无限制的阅读继续学习。如果你使用这个链接成为会员,你将支持我,而不需要额外的费用。提前感谢,再见!
我最近出版了一本关于使用 Python 解决金融领域实际任务的书。如果你有兴趣,我贴了一篇文章介绍这本书的内容。你可以在亚马逊或者 Packt 的网站上买到这本书。
生成对抗网络综合指南
从噪音中产生有意义的数据
《活的蒙娜丽莎》来自现实神经说话头部模型的少数镜头对抗学习
在我看来,这个(GANs)以及现在被提出的变体是 ML 过去 10 年中最有趣的想法
——Yann le Cun(脸书副总裁兼首席人工智能科学家)在他的 Quora 会议上
gan 是深度学习的最新奇迹之一。这些能够从垃圾数据中产生智慧。他们可以用来生成图像,视频,改变图像和更多!GANs 最近的研究集中在制造(人类的)深度赝品并检测它们。
GAN 本质上是一种神经网络架构(与其说是架构,不如说是框架),其中生成性模型与非生成性模型配对;生成模型因生成质量差而受到惩罚,而另一个模型因生成模型生成质量好而受到惩罚。所以在某种程度上,这些模特竞争来实现他们各自的目标。原文论文建议,
生成对抗网络只不过是一个通过对抗过程来估计生成模型的框架。
在本文中,我们将了解什么是 GANs,它们是如何工作的,并浏览一些它的用例。让我们先来看看主要内容:
内容
- 创成式 v/s 判别建模
- 生成性对抗性
- 几个使用案例(让你思考)
- 结论
生成式 v/s 判别建模
图片由作者提供,背景由像素提供
生成建模
任何涉及学习给定数据分布的趋势并生成非常类似或属于该分布的样本的建模都可以称为生成式建模。生成模型的一个非常常见的例子是根据前面的单词预测句子中的下一个单词。
关于文本生成的更多内容,你可以参考我的关于文本生成的文章
生成模型是具有联合概率分布 P(X,Y) ( 或者如果没有Y就只有 P(X) )的统计模型,其中 X 是自变量,Y 是因变量。
P(X,Y) 可以读作变量 X 和 Y 的概率分布。
甘也是生殖模型。但与其他的不同,新颖之处在于它的训练评估手段,也就是对手。
判别建模
而判别模型是对来自给定分布的数据进行判别(分类)的模型。辨别一幅给定的图片中有一只猫还是一只狗是辨别建模最简单的例子。
判别模型可以正式表示为 P(Y|X) ,其中 X 为自变量,Y 为因变量。
P(Y|X) 可以解释为“给定事件 X 已经发生,事件 Y 发生的概率”。
在 GANs 中,歧视者引入了我们将在下一节讨论的“敌对”性质。
通过谷歌开发者博客生成式 v/s 判别建模
生成性对抗性
在这里,我们讨论 GANs 的实际架构,看看它是如何工作的。
典型的甘
甘人就是这样被训练的。借助一个例子,我们将一个接一个地处理这个架构。假设我们想从随机数据中生成狗的图像。
噪音
这是随机分布的数据。这是转换成所需分布的分布(是的!在后台,GANs 将一个分布转换成另一个分布(即,他们将一个统计函数映射到另一个)。
来自真实分布的数据
这是实际的、期望的分布。GAN 的最终目标是从前面小节提到的噪声中产生(转换)属于该分布的数据。在我们的示例中,这是一组真实的狗图像,我们在这些图像上训练模型。
鉴别器
鉴别器
这是 GANs 区别于其他生成模型的地方。将一个生成模型与一个鉴别模型结合起来就是 GANs 的全部内容。让我们看看它是如何工作的。
鉴别器的唯一目的是将图像分类为真或假。所以,鉴别器有两个功能:
- 准确地将真实图像分类为真实的。
- 准确地将假图像分类为假的。
在我们的例子中,鉴别器可以是一个基本的基于 CNN 的二值图像分类器。
但这里有一个问题,当我们训练鉴别器从假图像中“辨别”真实图像时,生成器被训练来欺骗鉴别器,使其落入陷阱,将生成的图像分类为真实图像。
是的,我在暗示,鉴别器只不过是一个可训练的评估指标,它告诉我们生成的数据质量有多好/多差。
好吧,我想现在你对两家网队是如何竞争的有所了解了。我们将在下一小节讨论发电机的工作原理。
发电机
发电机
这是氮化镓的主要成分。这里,生成网络试图学习分布的趋势,并生成属于该分布的数据。
那么我们如何做到这一点呢?这要看情况。在我们的例子中,为了生成狗的图像,我们的噪声将经历一些去卷积层,最后,输出将是一个图像,希望是一只狗的。生成的图像将被鉴别器分类为真或假。如果生成的图像远非“真实”,则生成器将受到损失更大的惩罚,并且随着它在欺骗鉴别器方面取得进展,损失将会减少。
这是发电机网络背后的基本思想。架构可能因用例而异。有一些 GAN 架构是有条件的,也就是说,除了噪声之外,还有一些生成数据的条件。这样的添加可能会改变一点架构,但对手的基本思想仍然存在。
我们现在继续发电机和鉴别器的集体训练。
将发生器和鉴别器组合训练为“GAN”
所以,甘是伟大的!但是生成器和鉴别器的组合训练带来了收敛问题。让我们看看 GAN 是如何训练的。
训练时,发生器应与鉴别器隔离,反之亦然。简而言之,首先对鉴别器进行几个时期的训练,然后对发生器进行训练,这一序列反复进行。这就保证了训练的方向是正确的。否则,同时训练这两者就像击中一个移动的目标,失败的可能性更大。
如果你不能训练一个分类器来区分真实数据和生成数据,甚至是初始的随机生成器输出,你就不能开始 GAN 训练。
— 谷歌开发者博客
此外,随着生成器越来越擅长欺骗鉴别器,作为一个推论,鉴别器的准确性会降低。当鉴别器达到精度 0.5 时,这表明鉴别器已经开始随机预测,即在掷硬币时(这显然是不应该的)。这对发电机培训没有任何帮助,反而可能降低其性能。
因此,GANs 的收敛并不稳定,这是一个主要问题。
培训损失
GANs 论文将培训损失定义为:
通过谷歌开发者博客的 Minimax 损失
这是最小最大损失,鉴别器试图使其最大化,发生器试图使 log(1 - D(G(z))) 最小化,因为它不能触及 log(D(x))。
然而,论文还建议修改发电机的这一损耗,以使 log(D(G(z))最大化。
几个用例(让你思考)
- 普通的 GAN(GAN论文中描述的那些)可用于在不平衡或数据较少的情况下增加数据用于训练。
- 深度卷积生成对抗网络或 DCGAN 是具有用于图像生成的卷积层的普通 GAN
- pix2pix 模型可用于将结构的线框作为输入,并生成完整的结构作为输出。其他应用包括黑白图像着色。
- CycleGAN 用于将图像从一个域转换到另一个域,无需任何成对的训练样本
- DeepFake 生成和检测是 GANs 的最新研究课题之一,本质上是生成经过编辑或篡改的图像,肉眼看起来很逼真。这可以在照片/视频编辑软件的帮助下很容易地手动完成,因此很容易被误用。DeepFake 检测可以作为生成的一个推论。
我将在以后的文章中尝试介绍其中一些 gan 的实现。敬请关注!
结论
这篇文章的主要内容是生成模型的对抗性训练评估的概念。这为研究人员提供了许多分支,以提出类似的评估器来获得更好的模型性能。
我们还看到了生成式和判别式建模的概念,以及它们之间的区别。
我们研究了 gan 的工作原理及其背后的想法。总的来说,我们采取了务实的方法;我们讨论了 GANs 的培训方面以及实际培训网络时出现的问题。
最后,我们谈了一些众所周知的甘斯风味。
参考资料:
原文:https://arxiv.org/abs/1406.2661
有关 GANs 的数学转换方面的更多信息,请参考:
一步一步地建立导致 GANs 的推理。
towardsdatascience.com](/understanding-generative-adversarial-networks-gans-cd6e4651a29) [## 简介|生成性对抗网络|谷歌开发者
生成对抗网络(GANs)是机器学习领域一项令人兴奋的最新创新。甘是生殖的…
developers.google.com](https://developers.google.com/machine-learning/gan)