熊猫数据帧按连续的相同值分组
照片由 MichaelGaida 在 Pixabay 上拍摄
Python 编程技巧
按重复多次的连续相同值对熊猫数据帧进行分组
我们通常希望通过连续的值来分割熊猫数据帧。然而,在任何情况下处理连续值几乎总是不容易的,比如 SQL,Pandas 也是如此。此外,标准 SQL 提供了一堆窗口函数来促进这种操作,但是在 Pandas 中没有太多的窗口函数。幸运的是,Python 中有许多变通方法,有时甚至比经典的窗口函数更简单。
在本文中,我将演示如何通过重复一次或多次的连续相同值对 Pandas 数据帧进行分组。
问题定义
如果您仍然不太确定我们要解决的问题是什么,请不要担心,您将通过如下生成的示例数据了解这一点:
df = pd.DataFrame({
'item':['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M'],
'v':[1, 2, 3, 3, 3, 4, 5, 5, 6, 7, 8, 8, 9]
})
在截图中,绿线划分了我们预期的组。
在这个例子中,对这些值进行分组实际上非常容易。就简单groupby('v')
。
然而,它实际上是假设值v
必须单调递增。
如果值列不是单调递增的怎么办?
df = pd.DataFrame({
'item':['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N'],
'v':[1, 2, 3, 3, 3, 4, 5, 5, 6, 7, 8, 8, 9, 3]
})
在这个新示例中,我们再次添加了第 13 行,它的值为v == 3
。如果我们单纯的groupby('v')
,第 13 排会和 2、3、4 排放在同一个组,这不是我们想要的。
换句话说,第 13 行应该在一个单独的组中,因为它不是连续的。
直觉
基本思想是创建这样一个列,它可以根据。对于连续的原始值,它必须具有相同的值,但是当原始值改变时,它必须具有不同的值。我们可以用cumsum()
。以下是直观的步骤。
- 创建一个新列,将原始值下移一行
- 将移位值与原始值进行比较。如果相等,则为真,否则为假
- 在布尔列上使用
cumsum()
,得到的列可以用于分组
这是一个仅为直观目的而创建的示例数据帧。
为什么有效?如果你关注每一组:
shifted_not_equal_to_original
的第一个布尔值为True
,其余为False
(如果该组有多行)。因此,cumsum()
函数将使每组的第一行与前一组的最后一行有所不同。- 布尔值为
True
,因为如果前一行值不同于当前行值,则移位后的值不同于原始值。另一方面,从这个连续条纹的第二行开始,它将是False
,因为该值等于它的前一行。
解决办法
我知道直觉看起来很复杂,但是一旦你理解了这些,使用这种方法就很容易了,如下所示。
df.groupby((df['v'].shift() != df['v']).cumsum())
让我们验证这些组:
for k, v in df.groupby((df['v'].shift() != df['v']).cumsum()):
print(f'[group {k}]')
print(v)
非常重要的是,第 13 排与第 2、3、4 排分开分组,这正是我们所期待的。
因此,这种方法将能够对连续的值进行分组,而不管这些值后来是否重复,只要它不是连续的,就会创建另一个组。
摘要
事实上,我不会说熊猫提供了许多有用的窗口功能。但是,Python 中的 Pandas 是典型的不像 SQL 的“编程语言”。因此,它提供了更多的可能性,有时甚至能以更简单的方式解决问题。
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
medium.com](https://medium.com/@qiuyujx/membership)
如果你觉得我的文章有帮助,请考虑加入 Medium 会员来支持我和成千上万的其他作者!(点击上面的链接)
熊猫日期范围函数详细信息
考虑不同条件生成一系列日期
来源:王思然·哈德森
时间序列数据是以固定或恒定的时间间隔收集的数据集。时间序列数据用于跟踪长期预测,观察时间相关趋势或季节性趋势。这非常有用,通常用于金融机构、零售企业、房地产和许多其他类型的企业。但是如果你有数据但是没有记录日期呢?今年需要用去年的数据生成实验报告怎么办?或者,你可能需要在本季度使用上季度的数据。有时它是研究、分析或预测所必需的。
生成一系列日期
幸运的是熊猫有一个名为日期范围的函数来生成一系列日期或时间。我们将看到如何利用它来解决我们在工作中可能遇到的一些问题。在这里,我们将解决几个问题。
- 先说最简单的。以一天的频率生成一系列日期。
import pandas as pd
pd.date_range(start = '1/1/2020', end='1/15/2020')#Output:
DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05', '2020-01-06', '2020-01-07', '2020-01-08', '2020-01-09', '2020-01-10', '2020-01-11', '2020-01-12', '2020-01-13', '2020-01-14', '2020-01-15'], dtype='datetime64[ns]', freq='D')
2。生成一系列间隔两天的日期
pd.date_range('1/1/2020', '1/15/2020', freq='2D')#Output:
DatetimeIndex(['2020-01-01', '2020-01-03', '2020-01-05', '2020-01-07', '2020-01-09', '2020-01-11', '2020-01-13', '2020-01-15'], dtype='datetime64[ns]', freq='2D')
如果你注意到,我们不需要一直提到开始和结束。默认情况下,第一个日期作为开始日期,第二个日期作为结束日期。
3。制作一个只有工作日的时间序列
pd.date_range('1/1/2020', '1/15/2020', freq='B')#Output:
DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-06', '2020-01-07', '2020-01-08', '2020-01-09', '2020-01-10', '2020-01-13', '2020-01-14', '2020-01-15'], dtype='datetime64[ns]', freq='B')
在这里,“频率= 'B '表示工作日。
4.如果我们有开始日期,没有结束日期,该怎么办。在这种情况下,我们可以只输入一个句点,这意味着我们需要的日期或次数。
pd.date_range('1/1/2020', periods = 9, freq='B')#Output:
DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-06', '2020-01-07', '2020-01-08', '2020-01-09', '2020-01-10', '2020-01-13'], dtype='datetime64[ns]', freq='B')
5。如果我们有一个结束日期和一个周期(或者我们需要多少个日期),
pd.date_range(end='1/1/2020', periods = 5)#Output:
DatetimeIndex(['2019-12-28', '2019-12-29', '2019-12-30', '2019-12-31', '2020-01-01'], dtype='datetime64[ns]', freq='D')
如果我们不指定频率,date_range 函数将使用“freq='D '”。
6.频率不一定要以天数或工作日为单位。它可以是月、小时、分钟、秒和许多其他频率。让我们用一个 3M 的频率。
pd.date_range('1/1/2020', periods = 5, freq='3M')#Output:
DatetimeIndex(['2020-01-31', '2020-04-30', '2020-07-31', '2020-10-31', '2021-01-31'], dtype='datetime64[ns]', freq='3M')
以下是所有频率的完整列表:
7。找出每个月的业务月末日期。
使用“BM”作为上面频率表中的频率。提供开始日期和“周期”值。
pd.DataFrame(pd.date_range('1/1/2018', periods=12, freq='BM'), columns=['Date'])
这里是 2018 年每个月的最后一个工作日。
7。你的客户可能在不同的时区,比如在非洲:
pd.date_range('1/11/2019', periods=5, tz='Africa/Abidjan', freq='3H')#Output:
DatetimeIndex(['2019-01-11 00:00:00+00:00', '2019-01-11 03:00:00+00:00', '2019-01-11 06:00:00+00:00', '2019-01-11 09:00:00+00:00', '2019-01-11 12:00:00+00:00'], dtype='datetime64[ns, Africa/Abidjan]', freq='3H')
这里我使用的是每小时一次的频率。点击所有时区的链接。
下面是熊猫 date_range 函数的视频:
我希望它有帮助。
熊猫显示选项
当默认设置不符合您的要求时
马特·派克在 Unsplash 上的照片
Pandas 是一个非常强大的 Python 数据分析库,可以加速项目的预处理步骤。Pandas 的核心数据结构是 DataFrame ,它用带有标签的行和列的表格形式表示数据。Pandas 为数据帧提供了许多显示选项。默认设置在大多数情况下都适用,但您可能需要根据数据集的特征来调整它们。通过广泛的设置选项,pandas 允许创建一个定制的显示偏好。
显示选项可以用两个函数来处理:
- get_option:显示设置的选项
- set_option:允许改变选项
让我们导入一个示例数据帧,并通过示例来完成:
import pandas as pd
import numpy as npdf = pd.read_csv("/content/Telco-Customer-Churn.csv")df.shape
(7043, 21)df.head()
数据帧有 21 列,但只显示了 10 列。中间的用点表示。我们可以很容易地调整它,但让我们首先了解显示列的选项:
pd.get_option("display.max_columns")
10
不出所料,现在是 10 点。我们可以使用 set_option 函数和指示要显示多少列的类似语法来调整它:
pd.set_option("display.max_columns", 25)df.head()
现在所有的列都显示出来了。它们不适合屏幕,但我们可以使用底部的滚动条看到它们。
当我们拥有包含许多观察特征的宽数据框架时,此选项非常有用。
显示行也有类似的选项:
pd.get_option("display.max_rows")
60
因此,如果我们想要查看 100 行,我们可以类似地调整此设置:
pd.set_option("display.max_rows", 100)
还有一个调整列的显示宽度的选项。在某些情况下,数据集包含长字符串,这些字符串太长,无法使用默认设置显示。如果我们想查看完整的字符串,我们可以使用 max_colwidth 参数。让我们先来看看默认选项:
pd.get_option("display.max_colwidth")
50
因此,如果一个单元格包含的字符超过 50 个,我们就无法看到所有的字符。我创建了一个简单的数据框架来展示它在截断视图下的样子:
让我们增加宽度以查看完整的文本:
pd.set_option("display.max_colwidth", 150)
我们可能需要调整的另一个显示选项是浮点数的精度。默认值应该就可以了,但是可能会有一些极端的情况需要更高的精度:
pd.get_option("display.precision")
6
默认值为 6。让我们把它增加到 10。我们可能还想减少它,使它看起来更简单。
pd.set_option("display.precision", 10)
有更多的熊猫显示选项可以调整。我想强调一下你可能更经常需要的那些。如果你想看完整的列表,你可以随时访问熊猫文档。
如果你想了解更多关于熊猫的信息,这里有一个详细的熊猫帖子列表:
感谢您的阅读。如果您有任何反馈,请告诉我。
特定于熊猫数据类型的操作:访问器
举例说明。
蒂埃拉·马洛卡在 Unsplash 上拍摄的照片
注:除非另有说明,所有图片均由作者创作。
Pandas 是 Python 中一个广泛使用的数据分析和操作库。它提供了许多函数和方法来处理任何类型的数据。还有一些方法只适用于特定的数据类型。这些方法通过 4 个访问器来访问。
访问器扩展了 Pandas 的功能,并提供了特定的操作。例如,可以使用 dt 访问器从日期中提取月份。
在本帖中,我们将看到熊猫的 4 个访问器的各种操作,它们是:
- Str:字符串数据类型
- 分类数据类型
- Dt:日期时间、时间增量、周期数据类型
- 稀疏:稀疏数据类型
注意:我们将使用 Pandas 系列的示例,该系列也可以视为 DataFrame 列。
Str
Str 访问器提供了处理文本数据的方法。让我们首先创建一个包含文本单词的系列。
顾名思义,Split 根据指定的字符(默认为空格)拆分数据。然后,我们使用 explode 函数将每个分离的单词作为系列中的一个新项目。
猫是分裂的反义词。它将字符串串联成一系列。
upper 和 lower 方法分别将所有字符转换为大写和小写。
大写方法只将第一个字母转换成大写。
replace 方法可用于用另一个字符串替换整个或部分字符串。
len 方法返回一系列字符串的长度。
字符串访问器允许对字符串使用索引。例如,我们可以只选择前两个字符,如下所示:
我们也可以用 isalpha 方法检查是否所有字符都是字母顺序的。
如果至少有一个非字母字符,则返回 false。
Startswith 和 endswith 方法允许检查字符串是以特定字符开始还是结束。
我们还可以计算一个字符或一组字符在一个字符串中出现的次数。
lstrip 和 rstrip 方法可用于修剪字符串。例如,我们可以去掉 c 系列末尾的数字、空格和逗号。
Dt
Dt 访问器允许从日期时间数据中提取许多有用的属性。它还提供了操作方法。让我们首先创建一个简单的日期序列。
date_range 函数返回 datetimeindex。为了使用 dt 访问器,我们需要将其转换为一个序列。
我们可以通过简单地使用年、月和日属性从日期中提取年、月或日。
在某些情况下,我们可能需要日期的日历周。可以按如下方式完成:
还可以提取日期的星期几。从 0(周一)开始,一直到 6(周日)。
我们能够检查一个日期是一个月、一个季度还是一年的开始还是结束。让我们做一个例子来检查一个月的开始。季度和年度的语法类似。
猫
Cat 是分类数据类型的访问器。对于分类数据,使用分类数据类型比使用对象数据类型更有效。这在内存和速度方面有很大的不同,尤其是当数据基数较低时(即,与观察值相比,类别数较低)。
让我们首先创建一个具有分类数据类型的序列。
我们可以检查类别。
也可以重命名类别。
使用类别数据类型时要记住的一件重要事情是,新值必须在现有类别中。
例如,ser 中的类别是 A、B 和 c。我们不能将一个项目更新到除这三个类别之外的类别。如果我们试图这样做,就会得到一个值错误。
为了解决这个问题,我们可以添加新的类别,即使还没有数据点属于该类别。
我们现在可以将一个数据点更新为 d 类。
稀疏
Pandas 的稀疏数据结构允许高效地存储稀疏数据。谈到稀疏性,我们倾向于认为数组主要由零组成。然而,稀疏也可能是由于其他值(例如 NaN)。稀疏数据结构意味着通过省略匹配特定值(例如 0,1,NaN)的数据点来压缩对象。
让我们坚持传统的大部分是零的情况。下面的 numpy 数组包含 20 个 1 和 9980 个 0。
让我们创建两个系列。一个具有稀疏数据类型,一个具有浮点数据类型。
在内存使用方面会有巨大的差异。
内存使用量减少了 200 多倍。
稀疏数据结构的数据类型有两个元素。第一个是实际存储的元素的数据类型。第二个显示了未存储的稀疏元素。
在有序的情况下,稀疏性是由于零,所以零实际上没有被存储。
稀疏存取器提供了检查稀疏数据结构属性的方法。npoints 方法返回非 fill_value 点(实际存储的点)的数量。fill_value 点是稀疏度的值。
稀疏数组包含 20 个 1,其余值为零。
fill_value 方法显示稀疏元素,density 返回非 fill_value 点与整个数组的比率。
最后,sp_values 方法返回一个只包含非 fill_value 点的数组。
我们已经讨论了与访问器相关的方法的重要部分。当然,还有更多的方法,但我认为这些是你在数据分析过程中会经常用到的方法。他们肯定会让你的事情变得更容易。
您可以随时访问访问器官方文档的 API 来查看方法的完整列表。
感谢您的阅读。如果您有任何反馈,请告诉我。
熊猫相当于 10 个有用的 SQL 查询
…或者是面向 SQL 开发人员的熊猫
图片由PublicDomainPictures@Pixabay提供
如果你不知道,pandas 是一个用于数据操作和分析的 python 库。特别是,它提供了数据结构和操作来操作数字表和时间序列。这个名字来源于术语“面板数据”,这是一个计量经济学术语,指的是包含同一个人在多个时间段的观察结果的数据集。
基本上,它是 python 中处理表格的一种方式。在熊猫中,数据表被称为。
如标题所示,在本文中,我将向您展示一些最有用的 SQL 查询的 pandas 等价物。这既可以作为那些已经知道 SQL 的人对 pandas 的介绍,也可以作为您可能需要的常见 pandas 操作的备忘单。
对于下面的例子,我将使用这个数据集,它包含了美国 YouTube 视频的趋势数据。它由 40949 行和 16 列组成:video_id、trending_date、title、channel_title、category_id、
publish_time、tags、views、likes、unless、comment_count、
thumbnail_link、comments_disabled、ratings_disabled、
video_error_or_removed、description。
import numpy as np
import pandas as pd# Reading the csv file into a DataFrame
df = pd.read_csv('USvideos.csv')
默认情况下,Pandas 操作不会修改您正在处理的数据框;它们只是返回其他数据框,您需要将这些数据框赋给一个变量,或者如果您想要保存更改,请使用参数 inplace=True。对于下面的大多数例子,我们不改变我们的原始数据框,我们只是显示返回的结果。
1.挑选
SELECT col1, col2, ... FROM table
SELECT 语句用于从表中选择数据列。
要在 pandas 中做同样的事情,我们只需在数据框上使用数组符号,并在方括号内传递一个包含您想要选择的列名的列表。
df[['video_id', 'title']]
同样的事情也可以用下面的语法来实现,这样以后翻译 WHERE 语句就更容易了:
df.loc[:, ['video_id', 'title']]
SELECT DISTINCT col1, col2, ... FROM table
SELECT DISTINCT 语句只返回表中唯一的行。
数据框中可能存在重复值。如果您只想获得不同的行(删除重复的行),那么调用.drop_duplicates()
方法就很简单。根据该方法的名称判断,您可能认为它从初始数据框中移除了重复行,但它实际上是返回移除了重复行的新数据框。
df.loc[:, ['channel_title']].drop_duplicates()
SELECT TOP number col1, col2, ... FROM table
或
SELECT col1, col2, ... FROM table LIMIT number
SQL 中的 TOP 或 LIMIT 关键字用于限制从表顶部返回的行数。对于熊猫来说,用.head(number)
方法很容易做到这一点。Pandas 也有从数据帧末尾开始显示行的.tail(number)
方法。
df.loc[:, ['video_id', 'title']].head(5)
df.loc[:, ['video_id', 'title']].tail(5)
SQL 的 MIN()、MAX()、COUNT()、AVG()和 SUM()函数很容易翻译成 pandas:
SELECT MIN(col) FROM table
df.loc[:, ['views']].min()
SELECT MAX(col) FROM table
df.loc[:, ['views']].max()
SELECT COUNT(col) FROM table
df.loc[:, ['views']].count()
SELECT AVG(col) FROM table
df.loc[:, ['views']].mean()
SELECT SUM(col) FROM table
df.loc[:, ['views']].sum()
现在,如果我们想做这样的事情呢:
SELECT MAX(likes), MIN(dislikes) FROM table
?我们需要采取更多的步骤:
new_df = df.loc[:, ['likes']].max().rename({'likes': 'MAX(likes)'})
new_df['MIN(dislikes)'] = df.loc[:, ['dislikes']].min().values[0]
2.在哪里
SELECT col1, col2, ... FROM table WHERE condition
WHERE 子句用于仅提取满足指定条件的行。
回想一下我们到目前为止用于选择列的语法:
df.loc[:, ['col1', 'col2']]
在.loc
的方括号内有两个参数;到目前为止,我们只使用了第二个选项,它用于指定您想要选择的列。猜猜第一个参数是什么?用于选择行。Pandas 数据帧期望一个行索引或布尔标志的列表,它根据这个列表提取我们需要的行。到目前为止,我们只使用了表示“返回所有行”的符号:
。如果我们只想提取索引从 50 到 80 的行,我们可以在那个地方使用50:80
。
为了根据某种条件提取行,我们通常会传递一个由某种(矢量化)布尔运算返回的布尔标志数组。位置为 False 的行不会包含在结果中,只会返回位置为 True 的行。
使用等式和不等式运算符 =,<,< =,>,> =,!= 在条件是直截了当的。例如,要仅返回赞数> = 1000000 的行,我们可以使用:
df.loc[df['likes'] >= 1000000, ['video_id', 'title']]
请注意,我们之所以能做上面(df['likes'] >= 1000000
)的事情,是因为 pandas 已经覆盖了> =操作符的默认行为,因此它将操作符应用于元素,并返回我们需要的形状(行数)的布尔数组。
但是操作符 and,or,not 不是这样工作的。所以,我们就用 & 代替**, | 代替或, ~ 代替而不是。**
df.loc[(df['likes'] >= 1000000) & (df['dislikes'] <= 5000), ['video_id', 'title']].drop_duplicates()
SELECT col1, col2, ... FROM table WHERE colN IS NOT NULL
在 SQL 中,您可以使用IS NULL
或IS NOT NULL
来获取包含/不包含空值的行。
如何检查熊猫中的空值?我们将使用熊猫包中的isnull(array-like)
功能来实现。注意这不是数据框对象的方法,不要用df.isnull(...)
;而是做pd.isnull(df['column'])
。所以要小心。
下面的示例返回 description 不为 null 的所有行。
SELECT col1, col2, ... FROM table WHERE colN LIKE pattern
LIKE 关键字可以在 WHERE 子句中用来测试列是否匹配某个模式。
在 pandas 中,我们可以使用 python 的本地 re 正则表达式模块来完成同样的事情,甚至更多,因为 python 的 re 模块允许测试一组更丰富的模式,而不是 SQL 之类的。
我们将创建一个函数like(x, pattern)
,其中 x 是一个类似数组的对象,pattern 是一个包含我们想要测试的模式的字符串。这个函数首先将模式编译成一个正则表达式对象,然后我们可以使用.fullmatch(val)
方法根据我们的模式测试val
的值。为了对 x 向量中的每个元素进行测试,我们将使用 numpy 的vectorize(func)
函数为正则表达式匹配操作创建一个向量等价物。最后,我们将这个矢量化函数应用到我们的 x 输入向量。然后我们需要做的就是在.loc[]
中传递like(df['column'], pattern)
作为第一个参数。
import redef like(x, pattern):
r = re.compile(pattern)
vlike = np.vectorize(lambda val: bool(r.fullmatch(val)))
return vlike(x)
例如,下面的代码返回所有描述中包含单词“math”的视频。
df_notnull = df.loc[~pd.isnull(df['description']), :]
df_notnull.loc[like(df_notnull['description'], '.* math .*'), ['video_id', 'title']].drop_duplicates()
3.以…排序
SELECT col1, col2, ... FROM table ORDER BY col1, col2 ASC|DESC
这个 SQL 关键字用于按升序或降序对结果进行排序。
将它翻译成 pandas 很简单,只需在数据帧上调用.sort_values(by=['col1', ...], ascending=True/False)
方法。
df.loc[df['likes'] >= 2000000, ['video_id', 'title'] ].sort_values(by=['title'], ascending=True).drop_duplicates()
4.分组依据
SELECT col1, col2, ... FROM table GROUP BY colN
GROUP BY 语句对特定列中具有相同值的行进行分组。它通常与聚合函数(最小值、最大值、计数、总和、AVG)一起使用。
在 pandas 中,简单到调用.groupby(['col1', ...])
方法,然后调用.min()
、.max()
、.count()
、.sum
、.mean()
方法之一。
df.loc[:, ['channel_title', 'views', 'likes', 'dislikes'] ].groupby(['channel_title']).sum()
5.拥有
SELECT col1, col2, ... FROM table GROUP BY colN HAVING condition
HAVING 关键字用于根据组级别的条件过滤结果。
在熊猫中,我们有.filter(func)
方法,可以在groupby()
调用之后调用。我们需要向该方法传递一个函数,该函数将一个组的数据帧作为参数,并返回一个布尔值,该值决定该组是否包含在结果中。
但是如果我们想在 pandas 中一次做更多的事情,例如,在列上应用聚合函数,并基于组级别的条件过滤结果,我们需要在更多的步骤中这样做。而在 SQL 中,我们只需要一个查询就可以做到。
在下面的例子中,我们希望按 channel_title 分组,只允许表中至少有 100 个视频的频道,并对的浏览量、喜欢、不喜欢应用平均函数。
在 SQL 中,这将是:
**SELECT** channel_title, AVG(views), AVG(likes), AVG(dislikes)
**FROM** videos_table
**GROUP** **BY** channel_title
**HAVING** **COUNT**(video_id) **>=** 100;
在熊猫身上:
g = df.groupby(['channel_title'])
g = g.filter(lambda x: x['video_id'].count() > 100)
g = g.loc[:, ['channel_title', 'views', 'likes', 'dislikes']]
g = g.groupby(['channel_title']).mean()
6.插入
INSERT INTO table (column1, column2, ...) VALUES (value1, value2, ...)
这个 SQL 语句用于在表中插入新行。
在 pandas 中,我们可以使用.append()
方法在现有数据帧的末尾添加一个新的数据帧。我们将使用ignore_index=True
从旧数据帧的最后一行开始继续索引。
new_row = pd.DataFrame({'video_id': ['EkZGBdY0vlg'],
'channel_title': ['Professor Leonard'],
'title': ['Calculus 3 Lecture 13.3: Partial Derivatives']})
df = df.append(new_row, ignore_index=True)
7.删除
DELETE FROM table WHERE condition
DELETE 语句用于根据某种条件从表中删除现有的行。
在 pandas 中,我们可以使用.drop()
方法删除我们传入索引的行。与其他方法不同,这个方法不接受布尔数组作为输入。因此,我们必须将条件的输出转换为索引。我们可以通过np.where()
功能来实现。
在下面的例子中,我们删除了所有包含 channel_title!= ‘3Blue1Brown’ 。
df = df.drop(np.where(df['channel_title'] != '3Blue1Brown')[0])
8.改变
ALTER TABLE table ADD column
此 SQL 语句添加新列。
在熊猫身上,我们可以这样做:df['new_column'] = array-like
。
下面我们添加一个新列‘like _ ratio’:
df['like_ratio'] = df['likes'] / (df['likes'] + df['dislikes'])
ALTER TABLE table DROP COLUMN column
此 SQL 语句删除一列。
del df['column']
我们在熊猫身上就是这么做的。
例如,删除“comments_disabled”列将是:
del df['comments_disabled']
9.更新
**UPDATE** table_name
**SET** column1 **=** value1, column2 **=** value2, ...
**WHERE** condition;
UPDATE 语句用于根据某些条件改变表中的值。
为了在 python 中做到这一点,我们可以使用 numpy 的where()
函数。当我们用这个函数将一个布尔数组转换成索引数组时,我们在上面几行也看到了这个函数。这就是这个函数在只有一个参数的情况下所做的事情。这个函数可以接收 3 个相同大小的数组作为参数,第一个是布尔数组。让我们称它们为 c,x,y。它返回一个相同大小的数组,其中填充了以这种方式选择的来自 x 和 y 的元素:如果 c[i]为真,则选择 x[i]否则选择 y[i]。
要修改一个数据框列我们可以这样做:
df['column'] = np.where(condition, new_values, df['column'])
在下面的例子中,我们将赞数增加 100,其中 channel_title == 'Veritasium '。
这是之前的数据:
df.loc[df['channel_title'] == 'Veritasium', ['title', 'likes']]
将 Veritasium 频道的赞数增加 100:
df['likes'] = np.where(df['channel_title'] == 'Veritasium', df['likes']+100, df['likes'])
运行上述查询后:
10.加入
JOIN 子句用于根据两个或多个表之间的相关列来组合它们中的行。
为了展示连接的例子,我至少需要两个表,所以我将把目前使用的数据框分成两个更小的表。
df_titles = df.loc[:, ['video_id', 'title']].drop_duplicates()
df_stats = df.loc[:, ['video_id', 'views', 'likes', 'dislikes'] ].groupby('video_id').max()
# transform video_id from index to column
df_stats = df_stats.reset_index()
在 pandas 中进行连接很简单:数据帧有一个.join()
方法,我们可以这样使用:
df1.join(df2.set_index('key_column'), on='key_column')
还有更多类型的联接:内部联接、完全联接、左联接和右联接。
- 内部联接:返回在两个表中都有匹配值的行
- 完全(外部)联接:返回在任一表中具有匹配值的行
- LEFT JOIN:返回左侧表中的所有行,以及右侧表中匹配的行
- 右连接:返回右表中的所有行,以及左表中匹配的行
图片来自 w3schools
要在 pandas 中指定您想要的连接类型,您可以使用.join()
方法中的 how 参数。此参数可以是以下之一:“内部”、“外部”、“左侧”、“右侧”。
下面是“video_id”列上两个数据帧的内部连接示例。其他类型的连接以相同的方式完成,只需相应地更改“how”参数。
SQL 中的内部联接:
**SELECT** *
**FROM** df_titles
**INNER** **JOIN** df_stats
**ON** df_titles.video_id **=** df_stats.video_id;
熊猫的内心世界:
df_titles.join(df_stats.set_index('video_id'), on='video_id', how='inner')
这篇文章的笔记本可以在这里找到。
我希望这些信息对你有用,感谢你的阅读!
这篇文章也贴在我自己的网站这里。随便看看吧!
熊猫数据科学基础
数据导入和检查、缺失值、列和行操作等等
Python 是数据科学中的一种流行语言,当然,也是生产中最流行的机器学习语言。
然而,如果你看一下数据科学、分析和商业智能在各行各业和学术界的整体情况,你会发现 Python 有机会利用新的工具和技术成长。
作为一个例子,时间序列分析在 R 环境中取得了巨大的进展。这是因为它进入像fpp2
这样的丰富库的门槛很低。Python 在时间序列的某些领域仍然很受欢迎,但在预测领域要达到与 T1 相当的水平还有很长的路要走。
首先,它需要越来越多对用 Python 做数据科学感兴趣的从业者。对于新手来说,最重要的是确保进入门槛低。
这篇文章的目的是谈论 Python pandas
的实用程序来设置您的数据分析环境。这是为了展示学习少量命令就能开始更高级的建模。
熊猫是什么?
pandas
是 Python 中一个功能强大、灵活易用的数据挖掘库。它最初是在一家财务管理公司开发的。任何熟悉金融行业的人都知道,金融行业的许多数据科学实际上是时间序列分析。
事实上,熊猫这个名字来源于 panel data ,是计量经济学中使用的一种特殊类型的时间序列数据。如果你对计量经济学及其在数据科学中的应用感兴趣,看看这个:
数据科学家如何利用经济学家的工具箱
towardsdatascience.com](/econometrics-101-for-data-scientists-584f4f879c4f)
熊猫争夺数据
数据科学家花费大量时间(有人说是 80%)争论和准备数据进行分析。由于pandas
是专门为满足分析管道的这一部分而设计的,如果你知道它是如何工作的,以及如何最好地利用它进行数据准备,剩下的就很容易了。
因此,这是一条让数据分析做好准备的分析管道——从基本分析到高级建模。
导入数据
第一件事当然是安装pandas
库。
import pandas as pd
现在,您可以从各种来源导入数据。它可以是你电脑上的文件,网页上的文本,或者通过查询 SQL 数据库。
数据也有多种格式,如 csv、excel、json 等。
所以知道从哪里导入以及它是哪种格式将决定使用什么命令。这里有几个例子。
# improt a csv from the local machine or from the web
df = pd.read_csv("Your-Data-Path.csv")# importing an excel file from the computer
df = pd.read_excel("Your-Data-Path.xlsx")
数据检查
导入数据后,您需要检查一些东西,如数据结构、行数和列数、唯一值、NaN 值等。
# description of index, entries, columns, data types, memory info
df.info()# know the number of rows and columns
df.shape# check out first few rows
df.head()# if too many columns, list all of them
df.columns# number of unique values of a column
df["column_name"].nunique()# show all unique values of ONE column
df["column_name"].unique()# number of unique values in ALL columns altogether
df.columns.nunique()
缺少值
数据集中缺少值并不奇怪。首先,您需要检查是否有丢失的值:
# checking out number of missing values in each column
df.isnull().sum()# number of missing values as a percentage of total observations
df.isnull().sum()*100/len(df)
现在,一旦您发现有缺失值,您可以做一些事情—删除缺失值行、删除整个列、替换值—所有这些都取决于您的分析/建模需求。以下是一些基本命令:
# drop all rows containing null
df.dropna()# fill na values with strings
df.fillna("data missing")# fill na values with mean of columns
df.fillna(df.mean())
我写了一整篇关于处理缺失值的文章,如果你想看的话:
如何不因丢失数据而丢失有价值的信息
towardsdatascience.com](/dealing-with-missing-data-in-data-science-projects-e8ac7a4efdff)
列操作
我所说的列操作是指几件事情中的一件——选择列、删除列、重命名、添加新列、排序等等。在高级分析中,您可能希望创建一个基于现有列计算的新列(例如,基于现有的“出生日期”列创建“年龄”)。
# select a column by name
df["column_name"]# select multiple columns by column name
df[["column_name1", "column_name2"]] # notice the double brackets# select first 3 columns based on column locations
df.iloc[:, 0:4]# select columns 1, 2, 5
df.iloc[:, [1, 2, 5]]# drop a column
df.drop("column_name", axis = 1)# create a list of all columns in a dataframe
df.columns.tolist()# rename a column
df.rename(columns = {"old_name": "new_name"})# create a new column by multiplying an old column by 2
df["new_column_name"] = df["existing_column"] * 2# sorting a column value in an ascending order
df.sort_values(by = "column_name", ascending = True)
行操作
一旦你处理好了列,接下来就是行。出于多种原因,您需要使用行,最明显的是过滤或切片数据。此外,您可能希望在数据框架中添加新的观察值或移除一些现有的观察值。以下是过滤数据所需的一些命令:
# select rows 3 to 10
df.iloc[3:10, ]# select 3 to 10 rows AND columns 2 to 4
df.iloc[3:10, 2:5]# take a random sample of 10 rows
df.sample(10)# select rows with specific string
df[df["colum_name"].isin(["Batman"])]# conditional filtering: filter rows with >5
df.query("column_name > 5")
特例:准备时间序列数据
时间序列是一种不同的对象,不像的任何数据框架。原始数据通常没有为时间序列分析进行格式化,因此pandas
库将它们视为普通的数据帧,其中时间维度存储为字符串,而不是一个datetime
对象。因此,您需要将普通的数据帧转换为时间序列对象。
# convert Date column to a datetime object
df["Date"] = pd.to_datetime(df["Date"])# set Date as the index
df = df.set_index("Date")# add new columns by splitting index
df["Year"] = df.idex.year
df["Month"] = df.index.month
df["Weekday"] = df.index.weekday_name
关于时间序列数据准备的更多信息,这里有一篇文章:
一些简单的技巧和窍门来获得分析就绪的数据
towardsdatascience.com](/preparing-data-for-time-series-analysis-cd6f080e6836)
一锤定音
每个人都从不同的起点开始他们的数据科学之旅。然而,理解的程度和达到目标所需的时间有很大的不同,因为每个人采取不同的学习途径。如果有人遵循逻辑学习过程,使用 Python 学习数据争论的基础知识应该不难。在本文中,我用一些最常用的命令概述了逻辑顺序——数据导入、检查、缺失值、列操作、行操作。我希望这对您的数据科学之旅有用。
生物学家的熊猫
为什么生命科学家要学习如何编码以及从哪里开始
照片由émile Perron在 Unsplash 拍摄
赶上那班火车!
学习如何编码对许多生命科学家来说仍然是令人生畏的。研究生和博士后普遍感到,他们的背景教育没有让他们为挑战做好准备。学习新的计算技能的时间似乎已经过去了。“他们误了火车”。
事实是,从零开始学习如何编码是非常耗时的,对于我们大多数在高度竞争的环境中工作的人来说,在生产和发布我们的工作的无尽压力下,这可能感觉像是我们在给定时间内进行的智力努力的一个弯路。我们有很多事要做。我们总是有很多事情要做。然而,大多数人没有理解的是,研究人员没有必要成为尖端的程序员,拥有构建网络内容或移动应用的敏锐能力。边际水平的编码技能将使大多数科学家有能力自动化重复的任务,操纵数据和图像,并增加他们在分享和展示他们的工作时的资源。此外,越来越明显的是,在不久的将来,仅使用电子表格和标准软件来跟踪和操作信息将变得不切实际。缺乏理解基本代码和编写自己定制的脚本来分析和优化实验的能力的科学家将很难跟上步伐。今天看来具有挑战性的妥协,从长远来看肯定会有回报。花在笔记本电脑上的时间可能比许多实验更有价值。编程专业知识将使我们成为更好的科学家,我们研究问题的答案将更快更有效地到来。
也许你错过了一班火车,但还有许多其他的火车要赶。这篇短文是我试图在下一篇文章中给你一点启发。
边做边学&熊猫
你可能还没注意到,我不是数据科学家。事实上,我是那种’*经典’*的实验生物化学家,在整个大学期间从未写过一行代码。学习如何编程的动力来自于我已经读了一半博士学位的时候。随着我的数据越积越多,我发现自己花了几个小时重复相同的分析协议,要么优化参数,要么用新数据填充我的模型。我意识到,标准软件和电子表格是一个脆弱的东西。因此,我决定投身到编程世界中去,以获得能让我自动完成工作中枯燥部分的技能。这让我接触到了 Python、,这是我目前博士旅程中的一个游戏改变者。我在任何类型的数据和图像分析方面都变得更加省时,从我的同龄人中脱颖而出,并增加了我在各种数据驱动领域的职业前景。
最初,我的主要斗争是认识到我所学的东西的价值。我花了很多空闲时间,却很少应用那些*【知识】*。学习曲线似乎非常陡峭,感觉我可以用一个简单的 Excel 表完成所有这些任务。你知道那种感觉,对吧?在线平台通常依赖概念练习,对生命科学家没有明显的应用,并提供过多的指导和许多指令。当您决定从头开始编写自己的代码时,您会发现自己正看着一张空白页,不知道如何开始。两件事让我克服了这些困难,更快地跳到了那个学习曲线的上部: 边做边学 和**熊猫,**一个强大的 Python 的数据科学库。
本质上是指一种更具实践性的方法。阅读代码不是编码。您需要迈出这一步,开始在您的机器上编写代码。我试图用 Python 再现我在 Excel 或 OriginLab 中可以做的事情,例如,处理数据、绘图、应用统计测试以及将数学模型与我的实验数据相匹配。我不得不花费大量的时间调试和查看他人的代码来理解和修复我的错误,但最终,这是对我来说最有成效的策略:弄清楚如何让一些有意义的东西工作,调用非常支持的 python 社区(google 是你的朋友!),调查错误消息以修复我的问题,并在此过程中学习。
有许多语言,但 Python 对我来说是理想的——开源,非常直观,并拥有针对常见科学问题的大量科学库。熊猫只是让 Python 更加出色! Pandas 可以说是 Python 中最重要的数据科学库,也是说服非程序员深入研究编码的一个很好的工具。熊猫依赖于一种叫做DataFrame
的数据结构。这类似于一个 Excel 电子表格,包括各种内置函数,用很少的编程知识就可以操作和分析数据。
开始使用 Anaconda
*如果你认为自己是一个’*琼恩·雪诺’谈到代码(你一无所知!开头可能会引起愤怒。你需要与命令行交互,在黑色的屏幕上写下抽象的文字,只是为了下载软件和软件包,很快你就会感觉自己迷失在矩阵中。然而,Python 通过 Anaconda 提供了一种替代初始压力的方法(至少目前如此)。Anaconda 发行版像其他软件一样工作:从网页下载并安装。Anaconda 不仅包括 python 的最新版本,还包括许多用于数据科学的标准库,否则必须从命令行手动安装。这些包包括用于许多科学计算任务的numpy
和scipy
,以及 Python 中最常用的可视化库matplotlib
。事实上,熊猫是建立在numpy
之上的,与scipy
和matplotlib
配合得非常好。Anaconda 附带了其他开源平台,包括 R studio、和两个用于 python 的 ide(集成开发环境)(spyder和 jupyther )。ide 基本上是编写和编译代码的编辑器。有很多,这可能是另一个混乱的来源。然而,jupyter 通常是生命科学家的一个很好的起点。它们比许多其他 ide 更简单,并提供了一种笔记本式的风格,用户可以同时拥有代码、情节和笔记。
下面,我用一个 jupyter 笔记本对熊猫做了一个简短而温和的介绍。如果您的机器上安装了 anaconda,那么您已经准备好跟随它了。本指南使用了一个公众熟知的乳腺癌症诊断数据集。我的目标是说明你可以用有限的编程技能做多少关于熊猫的事情,也许会激励你从这里开始学习更多。在介质上处理代码的灵活性非常有限,所以我分享一个 github 链接,其中包含一个 jupyter 笔记本,上面有我在这里展示的所有例子。我们可以开始了吗?
读取&操纵数据
每一个 python 脚本都以几个import
命令开始,用户在这里设置他们想要使用的库/包,除了那些已经默认包含在 raw 语言中的库/包。你可以把它们想象成包含不同功能和参数的文件夹。按照惯例,我们import
将它们打包,并用它们名字的较短版本来表达,以避免在文档中写太多的单词。例如,我们使用import pandas as pd
,这样我们就不必每次想使用库时都写pandas
,只需写pd
。同样适用于np
和plt
而不是它们的全名。
下面的脚本显示了如何使用pandas
中的pd.read_csv
函数加载数据集。该功能直接从您机器上的文件夹中读取.txt
或.csv
文件,并以一种让您想起典型电子表格的格式显示数据。我们将函数的输出归属于一个变量(breast_cancer_data
),以便在脚本中使用它。
如何用熊猫读取文件
乳腺癌诊断数据集(来源)
我们的数据集包含 569 个样本(患者)、分类数据(诊断结果)和数值数据(与肿瘤形状和大小相关的 31 个属性,以及每个患者的 id)。我们现在已经准备好按照我们的意愿开始探索和操作数据。下面的脚本展示了几个简单操作的例子,只需一行代码就可以实现。
熊猫的基本操作
注意,这里我们只是检查给定函数的输出,而不是永久地改变数据。为了做到这一点,我们需要为每个操作的输出添加一个新的变量。或者,我们也可以使用参数inplace = True
,它告诉pandas
我们想要直接在原始表上实现动作。为了总结第一部分,我们可以使用上面的一些函数创建数据的子集,用于下一部分,我们称之为breast_cancer_data_subset
。
创建新表:breast_cancer_data_subset
乳腺癌数据子集
基本操作
当您开始探索大型数据集时,pandas
中的两个有用工具是pd.describe()
函数和pd.corr()
函数,前者返回所有数字列的汇总统计数据,后者返回数据框中所有列之间的相关性。下面你可以分别看到它们的样子。
乳腺癌数据子集描述()输出
乳腺癌数据子集 corr()输出
请注意,仅用两行简单的代码就可以从数据中检索出多少信息!这些函数只使用包含数字数据的列,因此没有显示诊断列。可以按照类似的模式应用其他简单的操作。这里还有几个例子。
总的来说,排序,计数,切片和基本的数学运算可以毫不费力地应用。所有函数通常都包含可选参数,这些参数可以让我们对它们的输出进行更多的控制。关于每个参数作用的详细信息可在pandas
文档中找到。
可视化数据
我们上面所做的所有操作都是可能的,因为pandas
是建立在科学计算的基础包numpy
之上的。同样,pandas
也整合了部分matplotlib
库来创建快速的数据可视化。为此,我们使用plot()
函数,并将变量(x
和y
)和绘图类型(kind
)设置为该函数的参数。
和熊猫一起策划
**
散点图:纹理与半径
就我个人而言,我宁愿直接使用matplotlib
库来绘制数据,在那里我对颜色、轴、大小和形状有更多的控制。然而,为了讨论的缘故,我将坚持用pandas
向你展示这些情节已经可以有多么丰富的信息和视觉吸引力。实际上,有另一个基于matplotlib
的数据可视化库叫做seaborn
,它与pandas.
配合得非常好。这是本文主要目标的一个小弯路,但是seaborn
是一个非常棒的相关性可视化工具,比单独使用matplotlib
来创建盒状图要好,并且对初学者来说非常用户友好。这里有一个例子。
相关矩阵的 seaborn 热图
seaborn pairplot 函数。诊断结果用于将数据分成两组
从这些例子中可以看出,seaborn
非常有助于初步了解多个变量之间的相关性。此外,它还提供了一种使用sns.boxplot
功能直接从数据框绘制箱线图的简单方法。下面的代码片段展示了如何操作。
seaborn 箱线图诊断与面积
通过结合pandas
和seaborn
可以做更多的事情,但是这只是一个展示,即使知道太少也可以做多少事情。
过滤和分组
最后,让我介绍两种方便的技术:使用简单条件参数的数据过滤和groupby
函数,可以说是pandas
提供的最好工具之一。条件遵循一个简单的模式,我们定义我们想要应用于一列或一行的条件(例如>
、<
或==
),我们以调用列的相同方式传递该条件。可以使用符号|
(或)和&
( 和)组合多个条件。这里有一些例子。
输出:肿瘤面积和周长分别大于 1000 和 180 的患者
最后,groupby
函数根据给定列中的分类或数字标签将数据分组。然后,数学运算可以分别应用于这些组中的每一组。在我们的示例中,诊断列中的两个标签(B 或 M)可用于此目的,使我们能够研究每个类别(良性和恶性肿瘤)中的数据有何不同。
breast _ cancer _ data _ subset . group by(‘诊断’)。中位数()
breast _ cancer _ data _ subset . group by(‘诊断’)。更正()
两组相关矩阵的 seaborn 热图
通过简单地应用groupby
函数,我们可以快速比较数据中不同的基础人群,并调查特征之间的差异是否具有统计相关性。我发现这个功能非常有用,我可以围绕它再写一篇文章。也许在后续的帖子里。
包装
这只是你可以用pandas
结合matplotlib
和seaborn
做的事情的冰山一角。也许这篇文章可以激励你去拿一个你自己的数据集并开始实验。从这里,您可以很快推断出其他库,如scipy
,它可以用来将数学模型与数据相匹配,并应用统计测试。
当然,这篇短文并没有为您提供 python 语言的所有构件。最终,你将不得不更深入地学习不同的数据类型(字符串、列表、数组和字典)以及类似循环的或列表理解的*。然而,通过用这种语言构建一些有意义的东西,而不仅仅是在线解决随机的任务,可能会给你一些额外的动力,让你继续前进,并在前进的道路上找到所有的东西。学习如何编程是一项真正的赋权技能,不仅可以提升你的职业前景,还可以平稳地导航这个技术时代。*
熊猫给新手:介绍第一部分
当谈到熊猫和蟒蛇时,我们都从同一个地方开始。照片由 Pexels 的 Victoria Borodinova 拍摄
对于那些刚刚开始学习数据科学的人来说,Python 编程语言是学习数据科学的先决条件,所以如果你不熟悉 Python,请熟悉一下,然后回到这里开始学习 Pandas。
你可以从我刚刚开始的一系列文章开始学习 Python,这些文章叫做数据科学所需的最小 Python。
谈到数据科学,工具箱中最重要的工具之一是 pandas,这是 Wes McKinney 在对冲基金任职期间开发的 Python 数据分析库。
在这整个系列的文章中,我们将使用 Anaconda ,它是一个面向数据科学和机器学习的奇特的 Python 包管理器。如果您不熟悉我刚刚谈到的内容,请继续观看这个视频,它将向您介绍 Anaconda 和 Jupyter Notebook,这是数据科学工作的核心。
您可以通过以下方式激活 conda 环境(虚拟环境):
$ conda activate [name of environment]# my environment is named `datascience` so$ conda activate datascience
激活 conda 虚拟环境后,您应该会在终端上看到:
(datascience)$
假设您的系统上安装了 miniconda 或 anaconda,您可以很容易地安装 pandas:
$ conda install pandas
我们还将使用 Jupyter Notebook 来编写代码,请继续
$ conda install -c conda-forge notebook
启动 Jupyter 笔记本:
$ jupyter notebook
熊猫是把所有东西粘在一起的粘合剂
随着我们在数据科学的更高层次上冒险进入机器学习领域,熊猫变得越来越重要,因为它允许数据在进入随机森林和神经网络等算法之前被“清洗”和“争论”。如果 ML 算法是 Doc,那么熊猫就是马蒂。
有导游的巴士旅游
我的最爱。文卡特·拉加文摄于 Pexels
我从小就喜欢去的地方之一是圣地亚哥动物园。我经常做的一件事就是一边喝着蓝月亮一边坐有导游的巴士旅游。
我们将做一些类似的事情,我将简单介绍一下你可以对熊猫做的一些事情。你独自面对蓝月亮。
这个中型系列的数据和灵感都来自 Ted Petrou 关于 Dunder Data 的优秀课程。
Pandas 主要处理表格数据:行和列。在这方面,它非常像一个 Excel 电子表格。
在 pandas 中,您将与两个主要对象交互,即系列和数据框。数据帧是由行和列组成的二维数据。
如果你不知道下面的代码是做什么的,没关系,我们稍后会详细讲解。我们在这里使用的数据是关于芝加哥的骑自行车的人,Illnoise。
数据框架:表格数据
Series 是一维数据或相对于 DataFrame 的单列数据:
系列:单列数据
如上所示,pandas 的一个亮点是它允许将数据从任何源文件加载到 Jupyter 笔记本会话中,无论是 CSV(逗号分隔)、XLSX(Excel)、SQL 还是 JSON。
我们经常做的第一件事就是通过使用head
方法来查看我们正在研究的数据集。默认情况下,head
将显示前五行数据。我们可以传递一个整数来控制我们希望看到多少行:
df.head(7)
前七排
如果我们想看到最后五行:
df.tail()
读入数据
我们使用read_csv
函数来加载 CSV 格式的数据。
我们将包含数据的文件路径作为字符串传递给 pandas 的read_csv
方法。在我的例子中,我使用的是我的 GitHub Repo 的 url,它保存了我将要使用的所有数据。我强烈推荐阅读关于熊猫read_csv
功能的文档,因为它是整个图书馆中最重要和最动态的功能之一。
过滤数据
我们可以用条件逻辑过滤熊猫数据帧的行。对于熟悉 SQL 的程序员来说,这就像使用WHERE
子句。
要仅检索wind_speed
大于 42.0 的行,我们可以这样做:
过滤器变量代表“过滤器”
我们可以像这样过滤多个条件:
这里我们过滤风速大于 42.0(我假设是每小时英里数)和骑车人的性别是女性的情况。正如我们看到的,它返回一个空数据集。
我们可以通过尝试相同的多个过滤器来验证我们没有犯某种导致空查询的错误,但是对于男性骑手。
我们也可以这样做:
查询:过滤的一种更简单的替代方法
Pandas 也有一个query
方法,它的能力有点受限,但是允许更简单和更可读的代码。和以前一样,熟悉 SQL 的程序员应该会对这种方法感到很舒服。
待续
《熊猫给新手》是一个中等系列,所以请关注下一个即将发布的教程 熊猫给新手:介绍第二部分 ,它将很快发布。
熊猫给新手:介绍第二部分
来自 Pexels 的 Victoria Borodinova 的照片
本文是上一篇文章的延续,上一篇文章开启了学习 Python 进行数据分析的旅程。你可以在这里查阅以前的文章:熊猫给新手:介绍第一部分。
对于那些刚刚开始学习数据科学的人来说,Python 编程语言是学习数据科学的先决条件,所以如果你不熟悉 Python,请熟悉一下,然后回到这里开始学习 Pandas。
你可以从我刚刚开始的一系列文章开始学习 Python,这些文章叫做数据科学所需的最小 Python。
作为一个提醒,我在这里做的是一个简短的旅行,只是一些你可以用熊猫做的事情。这是真正的深潜之前的深潜。
这个系列的数据和灵感都来自 Ted Petrou 关于 Dunder Data 的优秀课程。
先决条件
- 计算机编程语言
- 熊猫
- 朱皮特
一旦你把这三件事都准备好了,你就可以开始了。
聚合
我们上次停止了使用 pandas query
方法作为通过布尔条件逻辑进行常规过滤的替代方法。虽然有它的局限性,但是query
是一个可读性更好的方法。
今天我们继续讨论汇总,这是用一个数字汇总数据的行为。示例包括总和、平均值、中值、最小值和最大值。
让我们在不同数据集上尝试一下。
通过调用 mean 方法得到平均值。
students.mean()math score 66.089
reading score 69.169
writing score 68.054
dtype: float64
使用axis
参数来计算各行中所有分数(数学、阅读和写作)的总和:
scores = students[['math score', 'reading score', 'writing score']]scores.sum(axis=1).head(3)0 218
1 247
2 278
dtype: int64
非聚集方法
对数据执行计算,不一定要聚合数据。即round
方法:
scores.round(-1).head(3)math score reading score writing score0 70 70 701 70 90 902 90 100 90
在组内聚集
让我们获得单个列中唯一值的频率。
students['parental level of education'].value_counts()some college 226
associate's degree 222
high school 196
some high school 179
bachelor's degree 118
master's degree 59
Name: parental level of education, dtype: int64
使用groupby
方法创建一个组,然后应用和聚合。这里我们得到了每个性别的平均数学分数:
students.groupby('gender').agg(
mean_math_score=('math score', 'mean')
)mean_math_scoregenderfemale 63.633205male 68.728216
多重聚集
这里我们同时进行多个聚合。
students.groupby('gender').agg(
mean_math_score=('math score', 'mean'),
max_math_score=('math score', 'max'),
count_math_score=('math score', 'count')
)
我们可以从多个列创建组。
students.groupby(['gender', 'test preparation course']).agg(
mean_math_score=('math score', 'mean'),
max_math_score=('math score', 'max'),
count_math_score=('math score', 'count')
)
看起来,为两性考试做准备的学生比没有做准备的学生得分更高。
数据透视表
向信息消费者呈现信息的更好方法是使用pivot_table
函数,该函数与groupby
做同样的事情,但是使用一个分组列作为新列。
同样,同样的信息以更易读、更直观的格式呈现。
数据争论
让我们用一个新的数据集来检查缺失值的数据集
提供na_values
参数会将数据集中的空值标记为 NaN(不是数字)。
您可能还会遇到这样的数据集,其中所有的列都应该是一列的一部分。
我们可以使用melt
方法一个接一个地堆叠列。
合并数据集
学习熊猫库的这一部分时,了解一点 SQL 会派上用场。
在 pandas 中有多种连接数据的方法,但是您应该非常熟悉的一种方法是merge
方法,它基于一个或多个键连接数据帧中的行。它基本上是 SQL 连接的一个实现。
假设我有来自电影租赁数据库的以下数据:
使用merge
执行“内部”连接:
SQL (PostgreSQL)的等价形式如下:
SELECT * FROM customer
INNER JOIN payment
ON payment.customer_id = customer.customer_id
ORDER BY customer.first_name ASC
LIMIT 5;
时间序列分析
熊猫这个名字实际上来源于面板数据分析,该分析将横截面数据与在医学研究和经济学中最广泛使用的时间序列相结合。
假设我有以下数据,我知道它是时间序列数据,但没有用DatetimeIndex
指定它是时间序列:
p a0 0.749 28.961 1.093 67.812 0.920 55.153 0.960 78.624 0.912 60.15
我可以简单地将索引设置为一个DatetimeIndex
,用:
这导致:
p a1986-12-31 0.749 28.961987-12-31 1.093 67.811988-12-31 0.920 55.151989-12-31 0.960 78.621990-12-31 0.912 60.151991-12-31 1.054 45.541992-12-31 1.079 33.621993-12-31 1.525 44.581994-12-31 1.310 41.94
这里我们有一个数据集,其中 p 是因变量,a 是自变量。在运行名为 AR(1)的计量经济模型之前,我们必须滞后因变量来处理自相关,我们可以使用:
p a p_lagged1986-12-31 0.749 28.96 NaN1987-12-31 1.093 67.81 0.7491988-12-31 0.920 55.15 1.0931989-12-31 0.960 78.62 0.9201990-12-31 0.912 60.15 0.960
形象化
matplotlib
和pandas
的结合让我们可以在眨眼之间制作出基本的简单情节:
# Using the previous datasetbangla.plot();
pivot_scores.plot(kind='bar');
这就结束了我们对熊猫数据分析工具箱的简短巴士之旅。在我的下一系列文章中,我们将深入探讨更多内容。敬请关注!
熊猫小组:一个简单而详细的教程
Groupby 是一个很好的生成分析的工具,但是为了充分利用它并正确使用它,这里有一些众所周知的技巧
由德克·冯·隆-瓦格纳在 Unsplash 上拍摄的照片
Pandas groupby 是一个相当强大的数据分析工具。但是对于初学者来说使用起来并不是很直观,因为 groupby 的输出并不是 Pandas Dataframe 对象,而是 Pandasdata frame group by对象。DataFrame 对象可以很容易地被可视化,但对于 Pandas DataFrameGroupBy 对象来说却不是这样。如果一个物体不能被可视化,那么它就更难被操纵。
我在网上找到的一些教程要么包含了太多对用户来说不必要的信息,要么没有足够的信息让用户知道它是如何工作的。我认为包含数据科学家日常工作中经常使用的关键工具的指南肯定会有所帮助,这就是为什么我写这篇文章来帮助读者更好地了解 pandas groupby。
重要注意事项。
1。我假设读者在开始之前,已经知道了在 R、SQL、Excel(或其他工具)中 group by 计算是如何工作的。
2。所有代码都经过测试,它们适用于熊猫 1.0.3 。旧的熊猫版本可能会有错误。
每一节都将提供示例—可能有不同的方法来生成相同的结果,我会选择我经常使用的方法。
大纲如下:
- 使用创建分析。 groupby() 和**。agg()** :内置函数
- 使用创建分析。 groupby() 和**。agg()** :用户定义的函数和 lambda 函数
- 使用**。transform()** 将组统计数据连接到原始数据帧
- 分组处理时间序列
使用创建分析。 groupby() 和**。agg()** :内置函数
为了生成数据集中每个组的统计数据,我们需要根据一个或多个列将数据分类成组。
# group by a single column
df.groupby('column1')# group by multiple columns
df.groupby(['column1','column2'])
然后,我们决定想要创建什么样的统计数据。这可以用.agg()
来完成。使用.agg()
有几种不同的方式:
A.使用字典作为.agg()
的输入。
B .使用单个聚合函数或聚合函数列表作为输入。
C .使用命名聚合(Pandas 0.25.0 中的新功能)作为输入。
我将用下面的例子来演示这些不同的解决方案是如何工作的。
import pandas as pd
import numpy as np
df = pd.DataFrame(dict(Gender=['M', 'F', 'M', 'F',
'F', 'M', 'M', np.nan],
State=['NY','IL', 'NY', 'CA',
'IL', 'CA', 'CA', 'IL'],
col_1=[10,20,30,np.nan,40,50,60,70],
col_2=[1,6,2,4,6,9,np.nan,3]))
A .字典 什么时候用?— 当我们需要在不同的列上运行不同的聚合,并且我们不关心聚合列的名称是什么样子时。
对于字典中的每个键-值对,键是我们想要运行聚合的变量,值是聚合函数。
tbl = df.groupby(['Gender','State'])\
.agg({'col_1': ['mean', 'std'],
'col_2': [sum, 'size' ,'count']})
如果对于每一列,只使用一个聚合函数,那么我们就不必将聚合函数放在一个列表中。在这种情况下,tbl
将是单索引的,而不是多索引的。
tbl = df.groupby(['Gender','State'])\
.agg({'col_1': 'mean',
'col_2': sum})
B .单个聚合函数或者列表聚合函数 什么时候使用?— 当我们需要对所有列运行相同的聚合,并且我们不关心聚合列的名称是什么样子时。
如果我们想对每一列应用相同的集合函数,我们只需要在.agg()
中包含一个函数或一列函数。
tbl = df.groupby(['Gender','State'])\
.agg([min, max]) # a list of aggregation functions
如果我们只想查看选定列的结果,我们可以在代码中应用过滤器:
# filter by a single column
tbl = df.groupby(['Gender','State'])\
['col_1'].agg([min, max]) tbl = df.groupby(['Gender','State'])\
[['col_1']].agg([min, max])# filter by a multiple columns
tbl = df.groupby(['Gender','State'])\
['col_1', 'col_2'].agg([min, max])tbl = df.groupby(['Gender','State'])\
[['col_1', 'col_2']].agg([min, max])
**注。**如果我们按多列过滤,那么无论使用哪种方法,tbl.columns
都是多索引的。如果我们按单列过滤,那么[['col_1']]
使tbl.columns
成为多索引,而['col_1']
使tbl.columns
成为单索引。
C .命名聚合(熊猫≥ 0.25) 什么时候用?— 当我们需要在不同的列上运行不同的聚合时,我们希望在运行.agg()
后能够完全控制列名
在每个元组中,第一个元素是列名,第二个元素是聚合函数。
tbl = df.groupby(['Gender','State'])\
.agg(col_1_mean=('col_1','mean'),
col_1_max=('col_1',max),
col_2_sum=('col_2',sum))
关于 .agg()
的几点说明。
- 数据按列 A 和列 B 分组,但列 A 中有缺失值。在任一列中有缺失值的行将从使用
.agg()
生成的统计数据中排除。 - 对于使用 sum、max、min、【中值】、【均值】、【计数】(非空元素的计数)、、【标准】、、【唯一】、(不同元素的计数)创建的组统计,数据中缺失的值将从计算中排除。但是‘size’(所有元素的计数)仍然包括缺失值。
- 可以做
tbl.columns =["_".join(i) for i in tbl.columns.ravel()]
将多索引列转换成单索引列。 - 可以使用
tbl = tbl.reset_index()
将索引转换为表
的列。 - 在使用
.agg()
创建的表格中,组可能没有按照首选顺序排列。一个人可以
df['Gender'] = pd.Categorical(df['Gender'], ['F', 'M'])
df['State'] = pd.Categorical(df['State'], ['NY', 'CA', 'IL'])
在运行.agg()
之前,将列转换为用户指定级别的分类系列。(注。pd.Categorical
可能不适用于较老的熊猫版本)
使用创建分析。 groupby() 和**。agg()** :用户定义的函数和 lambda 函数
让我们看另一个例子,看看我们如何在.agg()
中使用用户定义的函数或 lambda 函数来计算统计数据。
df = pd.DataFrame(dict(StoreID=[1,1,1,1,2,2,2,2,2,2],
ProductID=['A01', 'A02', 'B01','C01',
'B01', 'B02', 'B03', 'C01',
'C02', 'C03'],
price=[10,20,50,100,50,60,70,100,150,200]))
我们希望计算每个商店的以下统计数据:
A .以“A”开头的产品数量
B .所有产品的列表
C .最高产品价格和最低产品价格的差异
D .产品价格的第一个分位数(第 25 个百分位数)
首先,我们定义一个函数来计算一个序列中以“A”开头的元素的数量。
def cnt_A(x):
ctr = 0
for item in x:
if item[0] == 'A':
ctr += 1
return ctr# If you prefer a Pythonic approach:
def cnt_A(x):
return (x.str[0] == 'A').sum()
然后,我们可以使用命名聚合+用户定义函数+ lambda 函数来优雅地完成所有计算。
df.groupby(['StoreID'])\
.agg(number_of_product_A =('ProductID', cnt_A),
product_list=('ProductID', lambda x: ', '.join(x)),
price_Q1 =('price', lambda x: np.percentile(x, 25)),
price_gap =('price', lambda x: x.max()-x.min())
)
当函数不复杂时,使用 lambda 函数会使您的生活更轻松。lambda x: x.max()-x.min()
和
def gap(x):
return x.max()-x.min()
生成相同的输出。
注。如果在有重复的时候你需要一个唯一的列表,你可以用lambda x: ', '.join(x.unique())
代替lambda x: ', '.join(x)
。
使用**。transform()** 将组统计信息附加到原始数据中
让我们使用上一节中的数据来看看如何使用.transform()
将组统计信息添加到原始数据中。
df = pd.DataFrame(dict(StoreID=[1,1,1,1,2,2,2,2,2,2],
ProductID=['A01', 'A02', 'B01','C01',
'B01', 'B02', 'B03', 'C01',
'C02', 'C03'],
price=[10,20,50,100,50,60,70,100,150,200]))df['cnt A in each store'] = df.groupby('StoreID')['ProductID']\
.transform(cnt_A)
使用.transform()
,我们可以轻松地将统计数据添加到原始数据集。
**注 1。**与.agg()
不同,.transform()
不以字典为输入。
**注二。**为了正确地追加数据,我们需要确保.groupby()
中使用的列中没有缺失值。(根据 Pandas 用户指南,.transform()
返回与被分组的对象索引相同(大小相同)的对象。)
示例—百分比计数:
df = pd.DataFrame(dict(bank_ID=[1,1,1,1,
2,2,2,2,2],
acct_type=['checking','checking',
'checking','credit',
'checking','credit',
'credit','credit',
'checking']))
问题:如何计算各银行账户类型的百分比?首先,我们计算每个 bank_ID + acct_type 组合的组总数:
tbl = df.groupby(['bank_ID', 'acct_type'])\
.agg(group_total=('acct_type','count'))\
.reset_index()
然后计算每个银行的总数,并使用.transform()
添加信息。
tbl['total count in each bank'] = tbl.groupby('bank_ID')\
['group_total']\
.transform(sum)
tbl['% in each bank'] = (tbl['group_total'] * 100.0
/ tbl['total count in each bank'])
另一个没有.transform()
的解决方案:只按 bank_ID 分组,用pd.merge()
把结果联接回tbl
。
分组处理时间序列
import datetime
df = pd.DataFrame(dict(acct_ID=['A102','A102','A102','A102',
'A102','A102','D276','D276',
'D276','D276','D276'],
transaction_time=[datetime.datetime(2016, 3, 1, 11, 0),
datetime.datetime(2016, 4, 12, 9, 0),
datetime.datetime(2016, 4, 14, 12, 0),
datetime.datetime(2016, 4, 14, 17, 0),
datetime.datetime(2016, 4, 20, 13, 0),
datetime.datetime(2016, 6, 11, 20, 0),
datetime.datetime(2018, 7, 11, 10, 0),
datetime.datetime(2018, 7, 12, 10, 0),
datetime.datetime(2018, 9, 24, 9, 0),
datetime.datetime(2018, 9, 24, 12, 0),
datetime.datetime(2018, 12, 20, 15, 0)
],
transaction_amount=[20, 100, 120, 100, 40,
60, 80, 200, 200, 80, 50]))
对于上面的交易数据,我们希望将以下各列添加到每个交易记录中:
- 交易行号(按交易时间排序)
- 前一笔交易的交易金额
- 前一笔交易与当前交易的交易金额差额
- 前一个交易与当前交易之间的时间间隔(以天为单位,向下舍入)
- 截至当前交易的所有交易的累计总额
- 截至当前交易的所有交易的累计最大值
- 截至上一笔交易的所有交易的累计总额
- 截至前一笔交易的所有交易的累计最大值
注。在进行以下计算之前,请确保先对数据进行排序。该表已经排序,但如果没有排序,您可以执行df.sort_values(by=['acct_ID','transaction_time'], inplace=True)
。
对于 1。,我们能做什么
df['rowID'] = df.groupby('acct_ID')['transaction_time']\
.rank(method='first', ascending=True)\
.astype(int)
两个人的。-6.,可以通过以下代码轻松完成:
df['prev_trans'] =df.groupby('acct_ID')['transaction_amount']\
.shift(1)
df['trans_diff'] =df.groupby('acct_ID')['transaction_amount']\
.diff(1)
df['time_diff'] =df.groupby('acct_ID')['transaction_time']\
.diff(1).dt.days
df['trans_cumsum']=df.groupby('acct_ID')['transaction_amount']\
.cumsum()
df['trans_cummax']=df.groupby('acct_ID')['transaction_amount']\
.cummax()
为了得到 7。和 8。,我们简单的把.shift(1)
加到 5。和 6。我们计算出:
df['trans_cumsum_prev'] = df.groupby('acct_ID')['trans_cumsum']\
.shift(1)
df['trans_cummax_prev'] = df.groupby('acct_ID')['trans_cummax']\
.shift(1)
所有这些计算的关键思想是,像
.rank()
、.shift()
、.diff()
、.cummax()
、.cumsum()
这样的窗口函数不仅适用于熊猫数据帧,也适用于熊猫分组对象。
让我们看看运行上面的计算后会得到什么。结果被分成两个表。
读者可以使用不同的参数来使用这些窗口函数,看看会发生什么(比如说,试试.diff(2)
或.shift(-1)
?).
读者提问 :
1。我们如何计算不同窗口大小的交易金额的移动平均值?(提示:组合.shift(1)
、.shift(2)
、…)
2。我们如何按照降序来计算事务行号?(提示:使用.rank()
中的ascending
参数——参见此链接。)
教程到此结束,感谢阅读。欢迎提出建议——欢迎在评论中发表新想法/更好的解决方案,这样其他人也可以看到它们。
熊猫分组——解释
如何高效利用熊猫的分组功能
Pandas 是一个非常强大的 Python 数据分析库,可以加速项目的预处理步骤。在这篇文章中,我将用许多例子来介绍熊猫的功能,帮助你全面理解这个功能。
Groupby 是一个多功能且易于使用的函数,有助于获得数据的概览。这使得探索数据集和揭示变量之间的潜在关系变得更加容易。
Groupby 最好通过例子来解释。我将使用 Kaggle 上可用的客户流失数据集。我只取了其中足以展示 groupby 函数每个细节的一部分。
一如既往,我们从进口熊猫开始:
import pandas as pd
import numpy as np
让我们快速看一下数据集:
df.shape
(7043, 9)df.head()
该数据集包括关于客户以及客户是否离职(即离开公司)的 8 个特征。
在对数据集应用 groupby 函数之前,让我们先看一个可视化的例子。可视化总是解释概念的好方法。假设我们有两个特征。一个是颜色,它是分类特征,另一个是数值特征,即值。我们希望按颜色对值分组,并计算不同颜色值的平均值**(或任何其他集合)。然后最后基于平均值对颜色进行分类。下图显示了此过程的步骤。**
让我们回到我们的数据集。为了查看性别是否在搅动中起作用,我们可以将性别和搅动列按性别分组。然后我们可以应用均值函数。
男性和女性的流失率非常接近。
如果我们不选择列并直接将 groupby 应用于数据框架,所有数值列都将根据聚合函数进行计算:
似乎所有的数字特征对男性和女性来说都大致相同。
我们还可以通过添加 sort_values 函数对结果进行排序:
默认情况下,它按升序排序。我们可以通过设置上升参数为假来改变它。
拥有光纤互联网服务的客户比其他客户更容易流失。
我们可以通过在方括号中传递列名来根据多个列进行分组:
“合同”栏有 3 个类别,“老年人”栏有 2 个类别,所以我们总共有 6 个组。对于每个组,计算平均“流失”率。
多个聚合函数
在某些情况下,应用 groupby 函数后,您可能希望查看不同组的计数和平均值。如果类分布不均衡,只查均值可能会造成错误的假设。您可以对 groupby 的结果应用多个聚合函数。它们不仅限于计数和均值,你可以将函数的名称作为参数传递给 agg() 函数。
as_index 参数
groupby 函数中的变量作为结果数据帧的索引返回。我们可以通过设置 as_index 参数为 false 来改变它。
让我们看看每月费用是否取决于合同类型。我们需要从数据集中提取“contract”和“MonthlyCharges”列,按“contract”分组,并对结果应用均值函数。
正如预期的那样,长期合同的平均月费用较低。
我们可以根据任务应用其他聚集函数。例如,我们可能希望看到不同 internet 服务类型的合同类型分布。由于两者都是分类变量,我们可以应用计数函数:
因为我们应用了 count 函数,所以返回的 dataframe 包括所有其他列,因为它可以计算值,而不管 dataframe 是什么。所有列上的值的数量都是相同的,所以我们可以只选择一列来查看值。熊猫的一个好处是通常有不止一种方法来完成一项任务。
这三行返回以下输出:
您也可以执行如下相同的任务,但返回的对象将是 dataframe:
请注意,一些聚合函数需要数值。例如,如果我们只有分类变量并试图应用均值函数,我们将得到一个错误:
我们可以多样化的例子,但基本的逻辑是相同的。Groupby 函数可用作探索性数据分析过程的第一步,因为它让我们了解数据集中变量之间的关系。
感谢阅读。如果您有任何反馈,请告诉我。
Pandas Groupby vs SQL Group By
举例说明
马库斯·斯皮斯克在 Unsplash 上的照片
Pandas 是 Python 的一个数据分析和操作库。SQL 是大多数关系数据库管理系统(RDBMS)用来管理数据库的编程语言。它们的共同点是 Pandas 和 SQL 都操作表格数据(即表格由行和列组成)。
虽然有不同的语法,但类似的操作或查询可以使用 Pandas 或 SQL 来完成。典型数据分析过程中最常见的操作之一是根据数字特征比较类别。两者在执行此类任务时效率都很高。
在本帖中,我们将做很多例子来掌握这些操作是如何用熊猫的 groupby 函数和 SQL 的 GROUP BY 语句完成的。
下图说明了“groupby”操作背后的逻辑。
Groupby 操作(图片由作者提供)
我们将使用 Kaggle 上提供的客户流失数据集。对于熊猫,数据集存储在“变动”数据帧中。对于 SQL,数据在“变动”表中。
这是数据集的快照。
(图片由作者提供)
有一些功能可以提供关于客户及其银行账户的信息。“已离开”栏显示客户是否离开银行。
我将定义一些有助于我们探索数据集的度量,并使用 Pandas 和 SQL 来计算它们。
我们开始吧。
基于国家/地区的流失率
这将有助于我们了解不同国家的流失率是否存在差异。将 exited 列按 geography 列分组并取平均值将得到结果。
熊猫
churn[['Geography','Exited']].groupby('Geography').mean()
(图片由作者提供)
SQL
SELECT Geography, AVG(Exited)
FROM CHURN
GROUP BY Geography;
(图片由作者提供)
主要的区别在于我们应用聚合函数的地方。SQL 允许在选择列时直接应用函数,而在 Pandas 的 groupby 函数之后应用。
基于国家和性别的流失率
SQL 和 Pandas 都允许基于多个列进行分组,这可以提供更多的洞察力。例如,我们可能想要检查性别如何影响不同国家的客户流失。
我们将首先按性别对平均流失率进行分组,然后按国家分组。
熊猫
churn[['Gender','Geography','Exited']]\
.groupby(['Gender','Geography']).mean()
(图片由作者提供)
SQL
SELECT Gender, Geography, AVG(Exited)
FROM CHURN
GROUP BY Gender, Geography
ORDER BY Gender, Geography;
(图片由作者提供)
我添加了 ORDER BY 子句来匹配 Pandas 返回的顺序,并使它看起来更有结构。
对于 Pandas 和 SQL,分组中列的顺序对结果帧的结构很重要。这些值不会改变。
每个国家的平均余额和客户总数
Pandas 和 SQL 都提供了对不同的列应用不同的聚合函数的方法。例如,我们可能想要检查每个国家的平均余额和客户总数。
这是怎么做的。
熊猫
churn[['Geography','Balance','Exited']].groupby(['Geography'])\
.agg({'Balance':'mean', 'Exited':'sum'})
(图片由作者提供)
我们向 agg (aggregate)函数传递一个字典,指定哪个函数应用于哪个列。
SQL
SELECT Geography, AVG(Balance), SUM(Exited)
FROM CHURN
GROUP BY Geography;
(图片由作者提供)
使用 SQL 很简单,因为它允许我们在选择列时指定函数。
基于产品数量的平均和总流失率
我们可以在同一个数字列上应用多个聚合函数。如果类别之间不平衡,建议同时检查平均值和计数。在这种情况下,只检查平均值可能会产生误导。
让我们来看看产品数量和客户流失之间的关系。我们将计算平均流失率和流失客户总数。
熊猫
churn[['NumOfProducts','Exited']]\
.groupby('NumOfProducts').agg(['mean','count'])
(图片由作者提供)
因为只有一个数值列,所以我们不必向 agg 函数传递字典。我们将只使用函数列表。
SQL
SELECT NumOfProducts, AVG(Exited), COUNT(Exited)
FROM CHURN
GROUP BY NumOfProducts;
(图片由作者提供)
仅仅检查平均值会产生误导,因为拥有 2 件以上产品的客户数量远远少于拥有 1 件或 2 件产品的客户数量。
结果排序怎么样?
分组的目标是根据计算出的数值列找到具有高值或低值的类别。因此,排序是分组操作的一个重要部分。
SQL 和熊猫在排序上都很灵活。我们可以根据任何计算值和任何顺序进行排序。
考虑前面的查询,我们根据产品数量检查客户流失。
让我们对结果进行排序。
熊猫
可以使用 sort_values 函数。我们通常只传递其值将用于排序的列的名称。但是,如果使用多个聚合函数,我们需要传递一个指示列索引的元组。
以下代码将根据平均流失率(Exited,mean)对结果进行排序。
churn[['NumOfProducts','Exited']]\
.groupby('NumOfProducts').agg(['mean','count'])\
.sort_values(by=('Exited','mean'))
(图片由作者提供)
SQL
我们只需要在末尾添加一个 ORDER BY 子句。
SELECT NumOfProducts, AVG(Exited), COUNT(Exited)
FROM CHURN
GROUP BY NumOfProducts
ORDER BY AVG(Exited);
(图片由作者提供)
默认情况下,Pandas 和 SQL 都按升序对值进行排序。为了按降序排序,只需修改代码如下:
- 熊猫:
sort_values(by=(‘Exited’,’mean’), ascending=False)
- SQL:
ORDER BY AVG(Exited) DESC;
结论
正如我们在示例中看到的,Pandas 和 SQL 的分组背后的逻辑非常相似。一旦你熟悉了其中的一种,学习另一种就相当容易了。这只是一个语法问题。
如果你正在从事或者打算从事数据科学领域的工作,我强烈推荐你学习熊猫和 SQL。
感谢您的阅读。如果您有任何反馈,请告诉我。
熊猫有阅读 Excel 文件的超能力
Pandas 有不同的阅读器将数据读入数据框。其中一个是 Excel 阅读器。你知道即使你有一些复杂的财务管理报告,阅读器的功能有多强大吗?
大多数公司都有财务部门,他们制作带有关键数字和表格的 Excel 文件,并配有复杂的辅助计算和图表。似乎他们喜欢复杂的文件,里面有一堆表格和一个封面,上面显示了后面表格中数字的汇总。这些文件相对来说比较容易被人类理解。但如果你想作为一名数据分析师进入数字领域,你会面临一些障碍,因为乍一看没有逻辑结构。将工作表作为数据框读取会导致表格混乱。这些表通常在一页上有许多带有不同标题和布局的表格。你知道熊猫有一些打开和处理这种 Excel 文件的超能力吗?
Pandas Excel-Reader 功能强大,您不必使用复杂的 Python 脚本来整理整个数据框架。让我们用两个(半设计的)案例来看看一些特性。
在我的 GitHub 库中,我添加了示例文件和一个 Jupyter 笔记本以及一些注释。
熊猫 Excel-读者准备
在我们开始使用 pandas read_excel
功能之前,我们必须安装 python 包xlrd
。只需使用您最喜欢的软件包管理器并安装它。
conda install xlrd# orpip install xlrd
熊猫准备打开和阅读 Excel 文件。我已经准备了两个文件来解释一些很棒的特性。
一个简单的例子
让我们从第一个文件开始,一个有一张纸的简单文件。该表包含两个表格,一些解释,一个图表和辅助计算。
财务报表使用的表格示例
如果你用pd.read_excel('Filename.xlsx')
读文件,你会得到一些杂乱无章的数据框。
试图读取文件时创建的数据帧
工作起来很费时间。但是不要害怕,熊猫会帮助你的!仔细看看这个表,我们会发现我们必须限制要读取的表的边界。熊猫 Excel 阅读器有一些很好的功能来传递列,哪一行是标题,应该读多少行。
让我们在这个简单的例子中深入研究这些参数。
第一个表位于 A 到 m 列之间,标题在第 2 行,我们需要读取 7 行。注意:不要计算标题行,这是隐含的。现在看看需要的参数。
为了定义标题,我们使用header
。Header 要求工作表的行从 0 开始!Excel 从一开始计数!在我们的工作表中,我们需要第 2 行,这意味着我们将 1 作为标题参数传递。
我们对 A-M 列感兴趣。Pandas Excel reader 支持选择列的 Excel 语法。在这种情况下,我们有"A:M"
,我们将它作为一个字符串传递给usecols
参数。我们需要的最后一个参数是熊猫应该读取的行数。相应的参数称为nrows,
,我们传递 7,因为我们需要从第二行开始的七行!
让我们读一读有熊猫的表格:
df = pd.read_excel("demosheet1.xlsx", header=1, usecols="A:M", nrows=7)
我们的数据框现在包含了我们想要的表的清晰表示
去杂乱的数据帧,随时可用!
很好,不是吗?现在让我们读这张纸的第二张表。
df_employees = pd.read_excel("200910_Produktivitätsreport August 2020.xlsx", header=12, usecols="A:G", nrows=10)
工作表中第二个表格的数据框
标题位于第 13 行(记住,pandas 从 0 开始,所以我们传递 12),我们读取列 A-G,并且我们正在读取接下来的 10 行。第二桌就这样。
这是一个只有一张纸的简单文件。正如开头所说,大多数文件都更复杂。它们可能包含几页纸和一个封面。让我们来看看熊猫 Excel reader 如何处理这种工作表。
分而治之—更复杂的工作表
想象一下下面的例子。我们有一份带有封面的管理报告。在文件中,我们还有另外三张包含更多信息/数字的表格。它们都有相似的结构,除了有有趣数字的表格外,它们还包含描述和进一步的(对我们来说没用的)计算。我们对封面不感兴趣,因为我们希望使用以下表格中的数据。
如果 Pandas 读取这种类型的文件,它将只解释文件中找到的第一个工作表。在我们的例子中:封面。
现在让我们弄清楚如何用熊猫 Excel 阅读器阅读其他工作表。
阅读器支持一个名为sheet_name
的参数,用于传递我们想要读取的工作表的编号或名称。让我们假设一个名为Sheet 1
的工作表位于封面后的第二个位置,我们想要读取这个工作表。我们有两种选择来阅读表单:
- 通过位置从 0 开始计数,其中 0 是第一个,1 是第二个,依此类推。
- 将工作表的名称作为字符串传递。在这种情况下
"Sheet 1"
# Pass the position
df = pd.read_excel("complex_one.xlsx", sheet_name=1)
# Pass the name as a string
df = pd.read_excel("complex_one.xlsx", sheet_name='Sheet 1')
因为我们只对从第十行开始的数据感兴趣,所以我们只需传递上面示例中描述的参数来访问数据。
df = pd.read_excel("complex_one.xlsx",
sheet_name='Sheet 1',
header=9,
usecols="A,B,D:H",
nrows=19, )
您可以看到,我一直在使用一个更复杂的字符串来选择列。我使用 A,B 列和 D 到 h 列,我跳过了 C,因为它没什么意思。我的标题在第十行(记住熊猫是从 0 开始计数的),我总共要读取 19 行。19,因为该工作表的作者决定有 19 个可能的数据行。即使使用较少。
包含大量 nan 的数据帧
要去掉带有 NaN 的行,只需使用
df_sheet1 = df_complex.dropna()
没有那些 nan 的数据帧。
那很容易。但是在我们的 Excel 文件中还有两张工作表。该阅读器支持读取多张纸。sheet_name
也可以处理工作表名称或编号的列表。你可以把名字和数字混在一起。
如果使用工作表列表,pandas 会返回一个包含数据框的字典。由于我们示例中的所有工作表都具有相同的结构,我们可以使用
df = pd.read_excel("complex_one.xlsx",
sheet_name=['Sheet 1', 2, 3],
header=9,
usecols="A,B,D:H",
nrows=19)
我们得到了三个结构相同的数据帧。现在,您可以进一步处理原始数据:
df_sheet1 = df_complex['Sheet 1'].dropna()
df_sheet2 = df_complex[2].dropna()
df_sheet3 = df_complex[3].dropna()
Pandas Excel reader 中最后一个有用的参数是设置列的数据类型。名为#
的专栏被熊猫解释为 float 。但是它应该是一个对象,因为它包含一个雇员号。Excel reader 有一个名为dtype
的参数,它需要一个带有。
Name_of_col: dtype
例如:
types = {
'#': object
}
df = pd.read_excel("complex_one.xlsx",
sheet_name=['Sheet 1', 2, 3],
header=9,
usecols="A,B,D:H",
nrows=19,
dtypes=types)
现在#
被解释为一个对象。不错!
下一步是什么,为什么?
熊猫 Excel 阅读器有更多的功能。阅读文档以获得更多灵感,在 pandas 中使用 Excel 表格可以做什么。
现在你可以从复杂的表格中读取原始数据,这些表格是为人类阅读而创建的。我们可以在阅读数据框的时候整理它们。下一步是用这些数据做出令人惊叹的东西。基于 Excel 创建由管理报告触发的仪表板、可视化和模型。或将数据添加到数据库等。由于 Excel 仍然是公司中几乎所有与数字打交道的人的首选工具,所以知道如何阅读和使用它们进行数据分析是很方便的。我希望你能学到一些新的东西,我很高兴看到笔记和评论。
[1]半设计,因为这些文件是基于我正在处理的真实世界场景。
熊猫加入 vs .合并
罗马卡夫在 Unsplash 上拍摄的照片
它们有什么作用,我们应该在什么时候使用它们?
我写了很多关于统计和算法的文章,但是为建模准备数据也是数据科学的一个重要部分。事实上,很有可能你会花更多的时间盯着你的数据,检查它,修补它的漏洞,而不是训练和调整你的模型。
因此,我们在收集、清理和对数据执行快速“健全性检查”分析方面做得越好,我们就能在建模上花费越多的时间(大多数人认为这更有趣)。为此,让我们看看如何快速组合来自不同数据框架的数据,并为分析做好准备。
数据
让我们假设我们是一家生产和销售回形针的公司的分析师。我们需要运行一些关于我们公司销售部门的报告,以了解他们的工作情况,并从以下字典中获得数据:
import numpy as np
import pandas as pd# Dataframe of number of sales made by an employee
sales = {'Tony': 103,
'Sally': 202,
'Randy': 380,
'Ellen': 101,
'Fred': 82
}# Dataframe of all employees and the region they work in
region = {'Tony': 'West',
'Sally': 'South',
'Carl': 'West',
'Archie': 'North',
'Randy': 'East',
'Ellen': 'South',
'Fred': np.nan,
'Mo': 'East',
'HanWei': np.nan,
}
我们可以从字典中创建两个独立的数据帧,如下所示:
# Make dataframes
sales_df = pd.DataFrame.from_dict(sales, orient='index',
columns=['sales'])
region_df = pd.DataFrame.from_dict(region, orient='index',
columns=['region'])
数据框架 sales_df 现在看起来像这样:
sales
Tony 103
Sally 202
Randy 380
Ellen 101
Fred 82
region_df 如下所示:
region
Tony West
Sally South
Carl West
Archie North
Randy East
Ellen South
Fred NaN
Mo East
HanWei NaN
我应该合并,加入,还是连接?
现在,让我们将所有数据合并到一个数据帧中。但是我们怎么做呢?
熊猫数据框架有很多类似 SQL 的功能。事实上,与 SQL 表相比,我更喜欢它们(全世界的数据分析师都对我虎视眈眈)。但是当我第一次开始用 Pandas 做许多类似 SQL 的东西时,我发现自己总是不确定是使用 join 还是 merge ,并且我经常互换使用它们(选择首先想到的)。那么我们应该在什么时候使用这些方法,它们之间到底有什么不同呢?好了,是时候不再困惑了!
加入
(如果你不熟悉什么是连接表,我写了这篇关于它的文章,我强烈建议你先读一读)
先从加入开始吧,因为这是最简单的一个。数据帧有一个叫做索引的东西。这是您的表的关键,如果我们知道索引,那么我们可以使用轻松地获取保存数据的行。loc 。如果你打印你的数据帧,你可以通过查看最左边的一栏来看索引是什么,或者我们可以更直接地使用**。索引**:
In: sales_df.indexOut: Index(['Tony', 'Sally', 'Randy', 'Ellen', 'Fred'],
dtype='object')
所以 sales_df 的指标就是我们销售人员的名字。顺便说一下,与 SQL 表的主键不同,数据帧的索引不必是唯一的。但是一个唯一的索引使我们的生活更容易,搜索数据帧的时间更短,所以它绝对是一个好东西。给定一个索引,我们可以像这样找到行数据:
In: sales_df.loc['Tony']Out: sales 103
Name: Tony, dtype: int64
好了,回到加入。 join 方法获取两个数据帧,在它们的索引上将它们连接起来(从技术上来说,您可以为左边的数据帧选择要连接的列)。让我们看看当我们通过 join 方法将两个数据帧组合在一起时会发生什么:
In: joined_df = region_df.join(sales_df, how='left')
print(joined_df)Out: region sales
Tony West 103.0
Sally South 202.0
Carl West NaN
Archie North NaN
Randy East 380.0
Ellen South 101.0
Fred NaN 82.0
Mo East NaN
HanWei NaN NaN
结果看起来像一个 SQL 连接的输出,它或多或少是这样的。 join 方法使用索引或它所调用的数据帧中的指定列,也就是左边的数据帧,作为连接键。因此,我们为左侧数据帧匹配的列不一定是它的索引。**但是对于正确的数据帧,连接键必须是它的索引。**我个人觉得更容易把 join 方法理解为基于索引的连接,如果我不想在索引上连接,就使用 merge (即将出现)。
在组合数据框架中有一些 nan。那是因为不是所有的员工都有销售。没有销售的那些在 sales_df 中不存在,但是我们仍然显示它们,因为我们执行了一个左连接(通过指定“how=left”),它从左数据帧 region_df 返回所有的行,不管是否有匹配。如果我们不想在我们的连接结果中显示任何 nan,我们将改为执行内部连接(通过指定“how=inner”)。
合并
基本上,合并和加入差不多。这两种方法都用于将两个数据帧组合在一起,但 merge 更通用,代价是需要更详细的输入。让我们看看如何使用合并创建与使用连接相同的组合数据帧:
In: joined_df_merge = region_df.merge(sales_df, how='left',
left_index=True,
right_index=True)
print(joined_df_merge)Out: region sales
Tony West 103.0
Sally South 202.0
Carl West NaN
Archie North NaN
Randy East 380.0
Ellen South 101.0
Fred NaN 82.0
Mo East NaN
HanWei NaN NaN
这与我们使用 join 时没有什么不同。但是 merge 允许我们为左右两个数据帧指定要连接的列。这里通过设置“左索引”和“右索引”等于真,我们让合并知道我们想要在索引上连接。我们得到了与之前使用 join 时相同的组合数据帧。
Merge 在我们不想在索引上连接的时候很有用。例如,假设我们想知道每个员工为他们的区域贡献了多少百分比。我们可以使用 groupby 来汇总每个地区的所有销售额。在下面的代码中, reset_index 用于将 region 从 data frame(grouped _ df)的索引转换为普通的列——是的,我们可以将它保留为索引并在其上连接,但是我想演示如何在列上使用 merge 。
In: grouped_df = joined_df_merge.groupby(by='region').sum()
grouped_df.reset_index(inplace=True)
print(grouped_df)Out: region sales
0 East 380.0
1 North 0.0
2 South 303.0
3 West 103.0
现在让使用 region 列合并 joined_df_merge 和 grouped_df。我们必须指定一个后缀,因为我们的两个数据框架(我们正在合并)都包含一个名为 sales 的列。后缀输入将指定的字符串附加到两个数据帧中具有相同名称的列的标签上。在我们的例子中,因为第二个 dataframe 的 sales 列实际上是整个地区的销售额,所以我们可以在它的标签后面加上“_region”来说明这一点。
In:employee_contrib = joined_df_merge.merge(grouped_df, how='left',
left_on='region',
right_on='region',
suffixes=('','_region'))
print(employee_contrib) Out: region sales sales_region
0 West 103.0 103.0
1 South 202.0 303.0
2 West NaN 103.0
3 North NaN 0.0
4 East 380.0 380.0
5 South 101.0 303.0
6 NaN 82.0 NaN
7 East NaN 380.0
8 NaN NaN NaN
哦不,我们的索引不见了!但是我们可以用 set_index 把它取回来(否则我们就不知道每行对应的是哪个员工):
In:employee_contrib = employee_contrib.set_index(joined_df_merge.index)
print(employee_contrib) Out: region sales sales_region
Tony West 103.0 103.0
Sally South 202.0 303.0
Carl West NaN 103.0
Archie North NaN 0.0
Randy East 380.0 380.0
Ellen South 101.0 303.0
Fred NaN 82.0 NaN
Mo East NaN 380.0
HanWei NaN NaN NaN
我们现在有了原始的 sales 列和一个新的 sales_region 列,它告诉我们一个地区的总销售额。让我们计算每个雇员占销售额的百分比,然后通过删除没有区域的观察值(弗雷德和韩伟)并用零填充销售列中的 NaNs 来清理我们的数据框架
In:# Drop NAs in region column
employee_contrib = employee_contrib.dropna(subset=['region'])# Fill NAs in sales column with 0
employee_contrib = employee_contrib.fillna({'sales': 0})employee_contrib['%_of_sales'] = employee_contrib['sales']/employee_contrib['sales_region']print(employee_contrib[['region','sales','%_of_sales']]\
.sort_values(by=['region','%_of_sales'])) Out: region sales %_of_sales
Mo East 0.0 0.000000
Randy East 380.0 1.000000
Archie North 0.0 NaN
Ellen South 101.0 0.333333
Sally South 202.0 0.666667
Carl West 0.0 0.000000
Tony West 103.0 1.000000
全部完成!请注意,北部地区没有销售额,因此有 NaN(不能被零除)。
结论
让我们快速回顾一下:
- 我们可以使用 join 和 merge 来合并 2 个数据帧。
- 当我们在索引上连接数据帧时, join 方法效果最好(尽管您可以为左边的数据帧指定另一个要连接的列)。
- merge 方法更加灵活,它允许我们指定索引之外的列来连接两个数据帧。如果索引在合并后被重置为计数器,我们可以使用 set_index 将其改回。
下一次,我们将了解如何通过 Pandas 的 concatenate 函数添加新的数据行(以及更多内容)。干杯!
如果你总体上喜欢这篇文章和我的写作,请考虑通过我的推荐链接注册 Medium 来支持我的写作。谢谢!T32