头图

Pandas是我们最常用的数据处理Python库之一。尽管您可能已经与它共事多年,但可能还有许多您尚未探索的实用方法。我将向您展示一些可能未曾听说但在数据整理方面非常实用的方法。

我目前日常使用的是pandas 2.2.0,这是本文时可用的最新版本。

 import pandas as pd
 import numpy as np
 
 print(pd.__version__)

1、agg

你可能已经熟悉使用pandas进行聚合操作,比如使用sum或min等方法。可能也已经结合groupby使用过这些方法。agg方法可以在DataFrame上执行一个或多个聚合操作。

通过将字典传递给agg方法,指示要为DataFrame的每一列计算哪些聚合操作(sum、mean、max等)。字典的键表示我们要对其执行聚合操作的列,而值表示我们要执行的操作。

 data = {
     "A": [1, 2, 3, 4],
     "B": [5, 6, 7, 8],
     "C": [9, 10, 11, 12],
 }
 
 df = pd.DataFrame(data)
 
 df.agg({"A": "sum", "B": "mean", "C": "max"})

agg并不仅限于为每列传递单个操作。在下一段代码中可以计算列A总和和平均值

 df.agg({"A": ["sum", "mean"], "B": "mean", "C": "max"})

在生成的DataFrame中,可以观察到一些NaN值,这些值对应于字典中没有请求的列和操作的组合。

下面我们添加一个分组列。要计算每个两个组内所有三列的平均值和总和。

 data = {
     "group": [1, 1, 2, 2],
     "A": [1, 2, 3, 4],
     "B": [5, 6, 7, 8],
     "C": [9, 10, 11, 12],
 }
 
 df = pd.DataFrame(data)
 
 df.groupby("group").agg(["mean", "sum"])

最后,就是我们可以将最终生成的列重新命名:

 df.groupby("group").agg(
     avg_a=("A", "mean"),
     sum_a=("A", "sum"),
     min_c=("C", "min"),
 )

2、assign

assign方法用于创建带有附加列的新DataFrame,并根据现有列或操作分配值。

 df = pd.DataFrame({"Value": [10, 15, 20, 25, 30, 35]})
 df.assign(value_cat=np.where(df["Value"] > 20, "high", "low"))

这种方法在链式操作中最有用,因为我们不一定对中间步骤感兴趣,并且并不想将中间结果添加到原始DataFrame中。

 df.assign(value_cat=np.where(df["Value"] > 20, "high", "low")).groupby(
     "value_cat"
 ).mean()

3、combine_first

combine_first方法用于组合两个Series(或DataFrame中的列),从第一个Series中选择值,并用第二个Series中的相应值填充任何缺失的值。

如果你对SQL熟悉的话,那么pandas的combine_first方法类似于SQL中的COALESCE函数。

 s1 = pd.Series([1, 2, np.nan, 4, np.nan, 6])
 s2 = pd.Series([10, np.nan, 30, 40, np.nan, 60])
 
 s1.combine_first(s2)

可以看到s1中缺失的值被s2的值填充。如果s2也是缺失值,则结果为缺失值。这种方法也可以用于DataFrame的列。

如果我们希望使用2列以上的列来更新缺失的值,我们也可以链接combine_firstmethods。

4、cumsum / cummin / cummax / cumprod

cumsum、cummin、cummax和cumprod方法用于计算Series或DataFrame中元素的累积和、最小值、最大值和乘积。

 data = {
     'A': [3, 1, 2, 0.5, 5, 10],
 }
 
 df = pd.DataFrame(data)
 df["cumsum"] = df["A"].cumsum()
 df["cummin"] = df["A"].cummin()
 df["cummax"] = df["A"].cummax()
 df["cumprod"] = df["A"].cumprod()
 df

5、cut / qcut

cut函数将数据划分为相同宽度的桶。这意味着每个桶都有相同的范围,但是每个桶中的数据点数量可能不同。

 df = pd.DataFrame(
     {
         "name": ["Alice", "Bob", "Charlie", "Dylan", "Eve", "Frank"],
         "years_of_exp": [10, 2, 0, 5, 6, 8],
     }
 )
 
 pd.cut(df["years_of_exp"], bins=3)

cut函数将所有观测值分类到三个长度相等(长度约为3.33)的桶中。

这里需要强调下区间符号。

 [0,10]:区间两边都闭合,即同时包含0和10
 (0,10):间隔两边都不闭合,即不包括0和10
 [0,10):区间左侧闭合,表示包含0,但不包含10。

我们可以定义桶的区间

 exp_bins = [0, 2, 5, 10]
 pd.cut(df["years_of_exp"], bins=exp_bins)

在输出中看到一个NaN值。这是因为最低值不包括在范围内。我们可以通过将include_lowest设置为True来解决这个问题。

还可以为桶分配自定义标签名称,这在特征工程时特别有用

 exp_labels = ["Junior level", "Mid level", "Senior level"]
 pd.cut(df["years_of_exp"], bins=exp_bins, include_lowest=True, labels=exp_labels)

qcut函数根据分位数将数据划分为桶。这确保了每个桶具有大致相同数量的数据点。

 pd.qcut(df["years_of_exp"], q=3)

使用qcut每个桶中都有2个值。cut根据区间划分数据,而qcut则根据分位数划分数据。

6、duplicate / drop_duplicate

duplicate方法返回一个boolean Series,指示DataFrame中的每个元素是否重复(True)或不重复(False)。

 data = {"A": [1, 2, 2, 3, 4, 4], "B": ["x", "y", "y", "z", "w", "w"]}
 df = pd.DataFrame(data)
 
 df.duplicated()

duplicate的默认设置 keep="first" ,保留第一个匹配的值,并将所有后续的观测值标记为duplicate.

也可以使用 keep="last" 保留最后的值,还可以使用keep=False 将所有的重复值标记为True

 df.duplicated(keep=False)

最后使用drop_duplduplicate方法直接删除重复项。drop_duplduplicate方法也可以设置keep参数

 df.drop_duplicates()

7、isin

isin方法用于筛选Series和dataframe,该方法返回一个布尔Series,显示列中的每个值是否在指定值范围内。

 data = {
     "Name": ["Alice", "Bob", "Charlie", "David", "Eve"],
     "Value": [1, 1, 1, 2, 2],
 }
 
 df = pd.DataFrame(data)
 
 selected_names = ["Alice", "David", "Eve"]
 df[df["Name"].isin(selected_names)]

8、merge_ordered

merge_ordered函数用来合并两个dataframe。当我们有两个具有顺序的dataframe,并且希望在保持索引的顺序的同时合并它们时(比如说时间序列),这个函数特别有用。

 df1 = pd.DataFrame(
     {
         "date": pd.date_range(start="2022-01-01", periods=5)[::-1],
         "value_df1": [10, 15, 20, 25, 30],
     }
 )
 
 df2 = pd.DataFrame(
     {
         "date": pd.date_range(start="2022-01-03", periods=4)[::-1],
         "value_df2": [100, 150, 250, 300],
     }
 )
 
 pd.merge_ordered(df1, df2, on="date", fill_method="ffill")

merge_ordered中连接的默认是outer join,所以fill_method需要设置一种方法来填充缺失值。

9、pct_change

pct_change用于计算Series或DataFrame中当前元素和先前元素之间的百分比变化。它用于分析价值随时间变化的百分比,特别是在金融时间序列数据中,例如股票价格。

 data = {
     "date": pd.date_range(start="2022-01-01", end="2022-01-05"),
     "price": [100, 105, 98, 110, 120],
 }
 
 df = pd.DataFrame(data).set_index("date")
 
 df["price"].pct_change()

10、select_dtypes

select_dtypes用于根据数据类型筛选DataFrame中的列。我们可以使用它来选择具有特定数据类型的列,例如数字类型(int64、float64)、对象类型(str、object)、布尔类型或日期时间类型等。

我们选择整数列和浮点列,即数字列。

 data = {
     "name": ["Alice", "Bob", "Charlie"],
     "age": [25, 30, 22],
     "salary": [50000.0, 60000.0, 45000.0],
     "date_joined": ["2022-01-01", "2022-02-15", "2021-12-10"],
     "remote_worker": [True, False, True]
 }
 
 df = pd.DataFrame(data)
 
 df.select_dtypes(include=["int64", "float64"])

或者可以直接这样写

 df.select_dtypes(include="number")

select_dtypes,还可以指定要排除哪些数据类型

 df.select_dtypes(exclude="object")

总结

pandas是一个非常庞大的库,我们最常用的只是其中的一些方法,可能还有许多尚未探索的实用方法。希望本文介绍的10各高级技巧可以帮你更有效地处理各种数据,更灵活地满足各种数据处理需求。

https://avoid.overfit.cn/post/2baf150e08a1418584b03f804de21b6d


deephub
119 声望91 粉丝