目录
Project-1.取名的重要性——给各类型数据取名方便项目开展
Project-4.存储和索引——存储和索引清洗完成的数据以便分析
Project-5.代码优化——让函数优化项目代码使得低耦合和可重用
Project-7.结束旅程——集成代码,根据应用类型、评分、下载量等分析应用的受欢迎度
任务一:使用函数读取 Google Play 和 APP Store 数据集
任务六:分别分析 App Store 和 Google Play 的受欢迎应用
任务七:使用嵌套循环分析 App Store 中受欢迎应用的特点
Project-7.结束旅程——集成代码,根据应用类型、评分、下载量等分析应用的受欢迎度
Project-1.取名的重要性——给各类型数据取名方便项目开展
恭喜
恭喜,你已经掌握了在
Python
中使用变量和各类数据。语法
- 将值存储到变量:
twenty = 20 result = 43 + 2**5 currency = 'USD'
- 更新存储在变量中的值:
x = 30 x += 10 # 与 x = x + 10 相同
- 四舍五入数字:
round(4.99) # 输出:5
- 使用引号创建字符串:
app_name = "* of Clans" app_rating = '3.5'
- 连接两个或多个字符串:
print('a' + 'b') # 打印出:ab print('a' + 'b' + 'c') # 打印出:abc
- 在变量类型之间转换:
int('4') str(4) float('4.3') str(4.3)
- 查找值的类型:
type(4) type('4')
概念
我们可以将数据赋值给变量,这个变量会存储在计算机内存中。
命名变量时,需要注意以下语法规则:
- 可以包括任何字母或数字(
a-z
,A-Z
,0-9
)以及下划线(_
);- 不能以数字开头;
- 不能和其它
Python
保留的特殊名字冲突。
=
运算符的含义与数学中的含义是不同的。在Python
中,=
运算符是赋值的意思,即将右侧的值分配给左侧的变量,但并非是 “等于” 或 “平等” 的意思。数据有整数
int
类型、浮点数float
类型等,不同类型的数值可以互转,不同类型的数值也可以相加,但是数字和字符之间不能直接相加。英文字母、数字、特殊字符都是字符,字符串可以存储任何字符,因此字符串不仅仅可以存储英文字母表中的字母,也能存储标点符号、数字!
字符串是以单引号
'
或双引号"
括起来的任意文本,可以通过+
让两个或多个字符串相连接,但切记只有相同类型之间的数据可以相加。转义字符
\
可以转义很多字符,比如\'
表示'
,\"
表示"
,\n
表示换行,\t
表示制表符,如果字符\
本身也要转义,所以\\
表示的字符就是\
。
Project-2.数据整理——整理应用市场数据¶
恭喜
恭喜,你已经掌握了:
- 通过使用包含列表的列表的形式读取大型数据集
- 使用列表和
for
循环来分析大型数据集语法
- 创建数据点列表:
row_1 = ['Facebook', 0.0, 'USD', 2974676, 3.5] row_2 = ['Instagram', 0.0, 'USD', 2161558, 4.5]
- 创建包含列表的列表:
data = [row_1, row_2]
- 检索列表的元素:
first_row = data[0] first_element_in_first_row = first_row[0] first_element_in_first_row = data[0][0] last_element_in_first_row = first_row[-1] last_element_in_first_row = data[0][-1]
- 检索多个列表元素并创建一个新列表:
row_1 = ['Facebook', 0.0, 'USD', 2974676, 3.5] rating_data_only = [row_1[3], row_1[4]]
- 执行列表切片:
row_1 = ['Facebook', 0.0, 'USD', 2974676, 3.5] second_to_fourth_element = row_1[1:4]
- 打开数据集文件并使用它创建列表列表:
opened_file = open('AppleStore.csv') from csv import reader read_file = reader(opened_file) apps_data = list(read_file)
- 使用
for
循环重复一个过程:row_1 = ['Facebook', 0.0, 'USD', 2974676, 3.5] for data_point in row_1: print(data_point)
概念
列表中的一个数据点对应一个值。
一组数据点构成一个数据集,列表是数据集的展示形式。
列表是我们可以用来存储数据集的数据类型。
使用
for
循环可以自动执行重复过程。
Project-3.数据清洗——清洗原始应用市场数据
恭喜
恭喜,你已经掌握了:
- 条件语句及其子句
if
,else
,elif
- 逻辑运算符
and
,or
- 比较运算符
==
,!=
,>
,>=
,<
,<=
我们一起回顾刚刚遇到的困难和总结出来的经验:
语法
- 使用
if
语句控制代码:if True: print(1) if 1 == 1: print(2) print(3)
- 结合多个条件:
if 3 > 1 and 'data' == 'data': print('Both conditions are true!') if 10 < 20 or 4 <= 5: print('At least one condition is true.')
- 构建更复杂的
if
语句:if (20 > 3 and 2 != 1) or 'Games' == 'Games': print('At least one condition is true.')
- 使用
else
子句:if False: print(1) else: print('The condition above was false.')
- 使用
elif
子句:if False: print(1) elif 30 > 5: print('The condition above was false.')
概念
- 我们可以使用
if
语句在代码中实现条件判断。elif
语句内的代码仅在同时满足以下2个情况下执行:
- 前面的
if
语句或前面的elif
语句解析为False
;- 在
elif
关键字后的条件计算结果为True
。True
和False
是布尔值。and
和or
是逻辑运算符,它们将两个或多个布尔值桥接在一起。- 我们可以将一个值
A
与另一个值B
进行比较,以确定:
A
是等于对B
,反之亦然(B
等于A
)。A
是不相B
等到B
,反之亦然。A
是更大的比B
,或反之亦然。A
是大于或等于B
,或反之亦然。A
是少比B
,或反之亦然。A
是小于或等于B
,或反之亦然。
Project-4.存储和索引——存储和索引清洗完成的数据以便分析
恭喜
恭喜,你已经掌握了:
- 使用字典计算总数和频率
我们一起回顾刚刚遇到的困难和总结出来的经验:
语法
- 创建字典:
# 方法 1 dictionary = {'key_1': 1, 'key_2': 2} # 方法 2 dictionary = {} dictionary['key_1'] = 1 dictionary['key_2'] = 2
- 检索单个词典值:
dictionary = {'key_1': 100, 'key_2': 200} dictionary['key_1'] # Outputs 100 dictionary['key_2'] # Outputs 200
- 检查字典中是否存在某个值作为键:
dictionary = {'key_1': 100, 'key_2': 200} 'key_1' in dictionary # 输出 True 'key_5' in dictionary # 输出 False 100 in dictionary # 输出 False
- 更新字典值:
dictionary = {'key_1': 100, 'key_2': 200} dictionary['key_1'] += 600 # 值将会变为 700
- 为数据集的列中的唯一值创建频率表:
frequency_table = {} for row in a_data_set: a_data_point = row[5] if a_data_point in frequency_table: frequency_table[a_data_point] += 1 else: frequency_table[a_data_point] = 1
概念
- 字典值的索引称为
key
。在'4+': 4433
中,字典键是'4+'
,字典值是4433
,'4+': 4433
是一个键值对。- 字典值可以是任何数据类型:字符串、整数、浮点数、布尔值、列表,甚至字典。但是,字典键除了列表和字典外,几乎可以是到目前为止我们所知道的任何数据类型。如果我们使用列表或字典作为字典键,则计算机会引发错误。
- 我们可以使用
in
运算符检查字典中是否存在某个值作为键。这个in
表达式返回的是一个布尔值。- 唯一值出现的次数也称为频率。将唯一值映射到其频率的表称为频率表。
- 当我们使用
for
循环访问字典时,默认情况下,循环是在字典键上进行的。
Project-5.代码优化——让函数优化项目代码使得低耦合和可重用
恭喜
恭喜,你已经掌握了:
- 创建和使用函数来加快工作流程
我们一起回顾刚刚遇到的困难和总结出来的经验:
语法
- 使用单个参数创建函数:
def square(number): return number**2
- 创建具有多个参数的函数:
def add(x, y): return x + y
- 在另一个函数的定义内重复使用一个函数:
def add_to_square(x): return square(x) + 1000 # 假设我们已经定义了square()
概念
- 通常,函数会包含:
- 它接受输入。
- 它对该输入进行处理。
- 它返回一个输出。
- 从结构上讲,函数由
def
语句,主体和return
语句组成。- 输入变量称为形参,参数采用的各种值称为实参。在square(number=6)中,number变量是形参。6是传递给形参number的实参。
- 通过名称传递的参数称为关键字参数,当我们使用多个关键字参数时,形参顺序不重要。
- 通过位置传递的参数称为位置参数。当我们使用多个位置参数时,必须按照函数定义的形参顺序输入实参。
- 调试更复杂的功能可能会更具挑战性,但是我们可以通过阅读报错中的traceback来发现错误。
Project-6.数据分析——对应用数据进行分析和处理
恭喜
恭喜,你已经掌握了:
- 函数的局部作用域和全局作用域的区别和特点
- 通过函数返回多个
return
或一个return
返回多个值- 认识了元组
我们一起回顾刚刚遇到的困难和总结出来的经验:
语法
- 使用默认参数初始化参数:
def add_value(x, constant=3.14): return x + constant
- 使用多个
return
语句:def sum_or_difference(a, b, do_sum): if do_sum: return a + b return a - b
- 返回多个变量:
def sum_and_difference(a, b): a_sum = a + b difference = a - b return a_sum, difference sum_1, diff_1 = sum_and_difference(15, 10)
概念
- 我们需要避免使用
Python
内置函数的名称来命名函数或变量,因为这会覆盖内置函数。- 每个内置函数在
Python
官方文档中都有详细记录,代码编辑器也会以高亮的相似展现。- 创建函数时,参数和
return
语句不是必需的。- 仅在调用函数时才执行函数定义中的代码。
- 调用函数时,函数内定义的变量将保存到临时内存中,函数完成运行后会立即被删除,可以实现函数中的临时存储器与与主程序关联的存储器隔离(主程序是功能定义之外的程序的一部分)。
- 程序中可以访问变量的部分通常称为作用域。据说在主程序中定义的变量在全局范围内,而在函数内部定义的变量在局部范围内。
- 如果变量在局部作用域中不可用,
Python
将搜索全局作用域,但相反情况并不适用。如果Python
在全局范围内找不到变量,则不会搜索本地范围。即使搜索了本地范围,与函数关联的内存也是临时的,因此搜索将毫无意义。
Project-7.结束旅程——集成代码,根据应用类型、评分、下载量等分析应用的受欢迎度
任务一:使用函数读取
Google Play
和APP Store
数据集在之前几个项目中,我们已经解决了若干小问题,这些小问题都来自于这个数据分析的项目。现在我们就要来集成小问题,并最终完成这个数据分析项目。
我们已经接触过来自
Google Play
的应用数据,现在我们还要加入来自APP Store
的数据一起分析:
- 一个来自
Google Play
的包含大约10000
个Android
应用程序的数据集,数据收集于2018年8月,数据集已保存在assets/dataset
文件夹中。- 一个来自
App Store
的包含大约7000个iOS
应用程序的数据集,数据收集于2017年7月,数据集已保存在assets/dataset
文件夹中。我们基于原有的代码进行修改,创建一个名为
explore_data()
的函数,该函数可以以可读的方式打印行:def explore_data(dataset, start, end, rows_and_columns=False): dataset_slice = dataset[start:end] for row in dataset_slice: print(row) print('\n') if rows_and_columns: print('Number of rows:', len(dataset)) print('Number of columns:', len(dataset[0]))
explore_data()
函数有以下功能:
- 接受四个参数:
dataset
,它应该是一个包含列表的列表。start
和end
,它们都应该是整数,表示数据集切片的开始和结束索引。rows_and_columns
,这应该是布尔值,默认参数为False
。- 使用
dataset[start:end]
分割数据集。- 循环遍历切片,对于每个迭代,打印一行并在该行之后使用
print('\n')
添加新行。
print('\n')
中的('\n')
是特殊字符,不会打印。相反,字符将添加新行,我们使用print('\n')
在行之间添加一些空白。- 如果
rows_and_columns
为True
,则打印行数和列数。
dataset
不应具有标题行,否则函数将打印错误的行数(与实际长度相比多打印一行)。接下来你需要完成:
- 结合之前我们已经写过的读取文件的代码,读取
Android
数据集和iOS
数据集,并将它们另存为包含列表的列表:
App Store
数据集存储在名为AppleStore.csv
的CSV
文件中,Google Play
数据集存储在名为googleplaystore.csv
的CSV
文件中。两个CSV
文件数据集已保存在assets/dataset
文件夹中。- 如果遇到名为
UnicodeDecodeError
的错误,请在open()
函数中添加encoding=“utf8”
,例如,使用open('AppleStore.csv', encoding='utf8')
。- 你需要分别将
Android
数据集的标题行和数据集内容存放到android_header
和android
两个不同的列表中,ios
同理要存放到ios_header
和ios
两个列表中。- 使用
Explore_data()
函数浏览两个数据集。
- 打印每个数据集的前
3
行,每个数据行之间要空一行。- 查找每个数据集的行数和列数。
小技巧
你会发现你既要查看上面的一长串文字,又要开始编程,屏幕滚动起来会非常麻烦。这里我告诉大家一个小技巧:
如图所示,我们新建一个
python3
的ipynb
文件,并将其拖拽到右侧,使得两个编程界面并排排列:任务二:删除错误数据和重复应用
在前面的任务中,我们已经可以正常地使用这两个数据集,并可以对数据进行了简要的分析。在正式开始分析之前,我们需要确保我们分析的数据是准确的,是我们想要的,因此我们需要:
- 寻找不准确的数据,并纠正或删除它。
- 检测重复数据,并删除重复数据。
由于我们只分析可以免费下载和安装的面向英语语言用户的应用程序,因此我们需要:
- 删除像爱奇艺、PPS这样的非英语应用
- 删除不免费的应用程序
准备数据进行分析的这个过程称为数据清理。数据清理是在分析之前完成的,它包括删除或更正错误的数据、删除重复的数据以及修改数据格式以适合进行分析。人们常说,数据清理会花80%的时间,实际分析数据的时间只有20%左右。但是数据清理是分析准确的大前提,当然在集成这个项目的过程中,你也能深刻体会到这句话。让我们从检测和删除错误数据开始对项目代码进行集成。
如果你认真浏览了
Google Play
数据集,你会发现一些应用程序有重复的条目。例如,Instagram有四个条目:for app in android: name = app[0] if name == 'Instagram': print(app)
总共有1181个应用程序出现多次:
在上方的代码中:
- 我们创建了两个列表:一个用于存储重复应用的名称,另一个用于存储唯一应用的名称。
- 循环遍历
android
数据集,每次迭代都进行以下操作:
- 我们将应用程序名保存到名为
name
的变量中。- 如果
name
已在unique_apps
列表中,则会将name
附加到duplicate_apps
列表中。- 否则(如果
name
不在unique_apps
列表中),我们将name
附加到unique_apps
列表中。在分析数据时,我们不希望对某些应用程序进行多次计数,因此需要删除这样重复的条目,并且每个应用程序只保留一个条目。我们可以随机删除重复的行,但如果有可能,我们希望保留下载量最大的那行。如果你检查我们为
我们可以使用该信息来建立一个删除重复项的标准。评论次数越多,数据应该越新,因此我们只保留评论数量最多的行,并删除其它条目。
综上所述,你需要完成:
创建一个名为
reviews_max
的空字典:
- 每个字典键是一个唯一的应用程序名称,对应的字典值是该应用程序的最高评论数。
- 循环浏览
Google Play
数据集,其中每次迭代需要完成:
- 将应用程序名称分配给名为
name
的变量。- 将评论数转换为浮点数。将其分配给一个名为
n_reviews
的变量。- 如果
name
已作为字典的键存在于reviews_max
字典中,并且reviews_max[name]<n_reviews
,则更新reviews_max
字典中该条目的评论数。- 如果
name
不作为字典的键存在于reviews_max
字典中,则在字典中创建一个新条目,其中键是name,值是reviews
的数量。请确保此处使用elif
而不是使用else
,否则每当reviews_max[name]<n_reviews
时,都会被计算为False
,并且会错误地更新评论数。- 最后为了确保计算正确,字典的预期长度是
9660
个条目。使用上面创建的词典删除重复行:
- 首先创建两个空列表:
android_clean
(它将存储我们新清理的数据集)和already_added
(它只存储应用程序名称)。- 循环浏览
Google Play
数据集,其中每次迭代需要完成:
- 将应用程序名称分配给名为
name
的变量。- 将评论数量转换为浮动,并将其分配给名为
n_reviews
的变量。- 如果
n_reviews
与应用程序名称name
的最大评论数相同(可以在评论最大词典中找到该数字),并且name
不在已添加的列表中:
- 将整行追加到
android_clean
列表(它最终将是一个包含列表的列表的存储已清理的数据集)。- 将应用程序名称
name
添加到already_added
列表中,这有助于我们跟踪已添加的应用程序。探索
android_clean
数据集,确保一切按预期进行,数据集应该有9660
行,以上两个步骤比较复杂。任务三:删除非英语应用
在上一步中,我们成功地删除了Google Play数据集中重复的应用程序条目。由于我们只分析面向英语语言用户的应用程序,然而,我们发现这两个数据集都有一些应用程序的名称不是以英语为语言,这表明它们不是针对讲英语的用户,因此将删除它们。有一个很好的方法,英语通常包括英语字母表中的26个字母、0到9之间的数字组成的数字、标点符号(
!, ?,;
)和其它符号(+,*,/
)。在编码中,有一个概念是 ASCII 码,每个字符都有一个与之相对应数字。例如,字符“a”对应的数字是97,字符“A”对应的数字是65,字符“爱”对应的数字是29233。我们可以使用order()内置函数获得每个字符的对应数量:
根据ASCII(美国信息交换标准码)系统,我们在英文文本中常用的字符对应的数字都在0到127之间。基于这个数字范围,我们可以建立一个函数来检测一个字符是否属于普通英语字符集。如果数字等于或小于127,则该字符属于通用英语字符集。
如果应用程序名称包含大于127的字符,则可能表示该应用程序具有非英文名称。然而,我们的应用程序名是以字符串的形式存储的,所以我们如何获取字符串的每个单独字符并检查其对应的数字?在
Python
中,字符串是可索引和可迭代的,这意味着我们可以使用索引来选择单个字符,我们还可以使用for
循环对字符串进行迭代。我们一定会发现该函数无法正确识别某些英语应用程序名称,如'Docs To Go™ Free Office Suite'和'Instachat