力扣pandas每日一题-----持续更新中

空值处理

dropna()

删除包含空值的行

默认情况下,dropna()会删除包含任何空值的行。

import pandas as pd
import numpy as np
 
# 创建一个包含空值的DataFrame
df = pd.DataFrame({
    'A': [1, np.nan, 3],
    'B': [4, 5, np.nan],
    'C': [7, 8, 9]
})
 
# 删除包含空值的行
df_dropped_rows = df.dropna()
 
print(df_dropped_rows)

在这个例子中,第二行和第三行都包含空值,但由于默认设置是删除包含空值的任何行,所以这两行都会被删除。然而,由于第三行在’B’列中有空值,而第二行在’A’列中有空值,且没有其他行在所有列中都非空,因此结果将是一个空DataFrame(在这个特定例子中)。

如果你想要删除包含空值的特定列的行,你可以使用subset参数。

# 只考虑'A'列和'B'列中的空值来删除行
df_dropped_rows_subset = df.dropna(subset=['A', 'B'])
 
print(df_dropped_rows_subset)

在这个修改后的例子中,只有第二行会因为’A’列中的空值而被删除。

删除包含空值的列

如果你想删除包含空值的列,你需要将axis参数设置为1(或'columns')。

# 删除包含空值的列
df_dropped_columns = df.dropna(axis=1)
 
print(df_dropped_columns)

在这个例子中,'B’列会被删除,因为它包含空值。

设置删除空值的阈值

你可以使用thresh参数来指定一个阈值,只有当行或列中的非空值数量少于这个阈值时,才会被删除。

# 删除非空值少于2个的行
df_dropped_rows_thresh = df.dropna(thresh=2)
 
print(df_dropped_rows_thresh)

在这个例子中,第二行会被删除,因为它只有1个非空值。

防止就地修改

drop()方法类似,dropna()默认返回一个新的DataFrame,而不会修改原始DataFrame。如果你希望直接修改原始DataFrame,可以使用inplace=True参数。

df.dropna(inplace=True)
print(df)  # 此时,原始DataFrame已被修改

fillna()

在Pandas中,fillna 方法用于填充 DataFrame 或 Series 中的缺失值(即 NaN 值)。它提供了多种选项来指定要填充的值或方法。以下是一些常用的用法示例:

基本用法

用单个值填充
import pandas as pd
import numpy as np
 
# 创建一个包含 NaN 值的 DataFrame
df = pd.DataFrame({
    'A': [1, 2, np.nan, 4],
    'B': [np.nan, 2, 3, 4],
    'C': [1, np.nan, np.nan, 4]
})
 
# 用单个值填充所有 NaN
df_filled = df.fillna(0)
print(df_filled)
用不同的值填充不同列

1158. 市场分析 I

# 用字典指定每列要填充的值
df_filled_diff = df.fillna({'A': 0, 'B': 1, 'C': 2})
print(df_filled_diff)
用前一个有效值填充(前向填充)
# 使用前一个有效值填充
df_filled_ffill = df.fillna(method='ffill')
print(df_filled_ffill)
用后一个有效值填充(后向填充)
# 使用后一个有效值填充
df_filled_bfill = df.fillna(method='bfill')
print(df_filled_bfill)
用列的均值填充
# 使用列的均值填充 NaN 值
df_filled_mean = df.fillna(df.mean())
print(df_filled_mean)
用插值法填充
# 使用插值法填充(线性插值)
df_filled_interpolate = df.interpolate()
print(df_filled_interpolate)

注意事项

  • fillna 方法返回一个新的 DataFrame 或 Series,不会修改原始数据。
  • 可以使用 inplace=True 参数直接修改原始数据,例如 df.fillna(0, inplace=True)
  • method='ffill'method='bfill' 分别对应于前向填充和后向填充,适用于时间序列数据。
  • 插值法(interpolate)通常用于处理时间序列数据中的缺失值。

判断DataFrame为空

检查形状(shape)

通过检查 DataFrame 的形状(即行数和列数),可以判断它是否为空。如果行数为0或列数为0,则可以认为它是空的。

import pandas as pd
 
# 创建一个空的 DataFrame
df = pd.DataFrame()
 
# 判断 DataFrame 是否为空
if df.shape[0] == 0 or df.shape[1] == 0:
    print("DataFrame is empty")
else:
    print("DataFrame is not empty")

使用 empty 属性

Pandas 的 DataFrame 对象有一个 empty 属性,它直接返回一个布尔值,指示 DataFrame 是否为空(即没有任何行)。注意,这个属性只检查行数,不检查列数。因此,如果一个 DataFrame 有列但没有行,它仍然会被认为是空的。

import pandas as pd
 
# 创建一个空的 DataFrame
df = pd.DataFrame()
 
# 判断 DataFrame 是否为空
if df.empty:
    print("DataFrame is empty")
else:
    print("DataFrame is not empty")

结合使用 shapeempty

如果你希望更严格地检查 DataFrame 是否既没有行也没有列,可以结合使用 shapeempty 属性。

import pandas as pd
 
# 创建一个空的 DataFrame
df = pd.DataFrame()
 
# 判断 DataFrame 是否为空(既没有行也没有列)
if df.empty and df.shape[1] == 0:
    print("DataFrame is completely empty (no rows and no columns)")
else:
    print("DataFrame is not completely empty")

检查数据内容

586. 订单最多的客户

在某些情况下,你可能还需要检查 DataFrame 中的数据内容是否为 NaN 或其他特定值。不过,这通常用于更复杂的场景,而不是简单地判断 DataFrame 是否为空。

import pandas as pd
import numpy as np
 
# 创建一个全是 NaN 的 DataFrame
df = pd.DataFrame(np.nan, index=[0], columns=[0])
 
# 判断 DataFrame 是否真正“内容为空”(即所有值都是 NaN)
if df.isnull().values.all():
    print("DataFrame has no non-NaN values")
else:
    print("DataFrame has non-NaN values")

重复值

duplicated()

Pandas 中,duplicated() 是一个非常实用的方法,用于标识重复的行。它返回一个布尔值的 Series,标识哪些行是重复的,默认情况下标识除了第一次出现的所有重复行。

duplicated() 方法的基本用法:

DataFrame.duplicated(subset=None, keep='first')

参数说明:

  • subset:用于判断重复的列。如果没有指定,默认会检查所有列。

  • keep

    :控制哪一条记录被标记为重复:

    • 'first'(默认):标记除了第一次出现的记录外,其他重复的行。
    • 'last':标记除了最后一次出现的记录外,其他重复的行。
    • False:标记所有重复的行(包括第一次和最后一次)。

返回值:

duplicated() 返回一个布尔类型的 Series,标记哪些行是重复的。True 表示该行是重复的,False 表示该行是第一次出现。


例子:

假设有一个包含重复数据的 DataFrame

import pandas as pd

# 示例数据
data = {
    'id': [1, 2, 2, 3, 4, 4, 5],
    'name': ['Alice', 'Bob', 'Bob', 'Charlie', 'David', 'David', 'Eve'],
    'age': [25, 30, 30, 35, 40, 40, 45]
}

df = pd.DataFrame(data)

print(df)

输出:

id     name  age
0   1    Alice   25
1   2      Bob   30
2   2      Bob   30
3   3  Charlie   35
4   4    David   40
5   4    David   40
6   5      Eve   45
示例 1:标记重复的行(默认 keep='first'
# 使用 duplicated() 查找重复的行
duplicates = df.duplicated()

print(duplicates)

输出:

0    False
1    False
2     True
3    False
4    False
5     True
6    False
dtype: bool
  • 解释duplicated() 会标记除第一次出现的记录之外的所有重复记录。返回的布尔值 Series 表示哪些行是重复的,True 表示是重复的行,False 表示是第一次出现的行。
  • 例如,id=2id=4 的行是重复的,所以下标为 2 和 5 的行会被标记为 True
示例 2:标记最后一次出现的重复记录(keep='last'
# 使用 duplicated() 查找重复的行,但保留最后一次出现的记录
duplicates_last = df.duplicated(keep='last')

print(duplicates_last)

输出:

0    False
1    False
2     True
3    False
4    False
5     True
6    False
dtype: bool
  • 解释keep='last' 时,duplicated() 会标记除了最后一次出现的记录外,其他重复记录为 True。所以,id=2id=4 的第二次出现会被标记为 True,而第一次出现会标记为 False
示例 3:标记所有重复记录(keep=False

585. 2016年的投资

619. 只出现一次的最大数字

# 使用 duplicated() 查找所有的重复行,包括第一次和最后一次
duplicates_all = df.duplicated(keep=False)

print(duplicates_all)

输出:

0    False
1     True
2     True
3    False
4     True
5     True
6    False
dtype: bool
  • 解释keep=False 时,duplicated() 会标记所有的重复记录为 True,包括第一次出现的记录。
示例 4:根据特定列判断重复项
# 使用 'id' 列来判断重复
duplicates_subset = df.duplicated(subset=['id'])

print(duplicates_subset)

输出:

0    False
1    False
2     True
3    False
4    False
5     True
6    False
dtype: bool
  • 解释subset=['id'] 表示只根据 id 列来判断重复项。id=2id=4 会被标记为重复,第二次出现时标记为 True,第一次出现时标记为 False
示例 5:删除重复行(基于 duplicated()

你可以使用 duplicated() 来标记重复项,然后结合 DataFrame 的布尔索引删除重复项。例如,要删除所有重复的行,保留第一次出现的记录:

df_no_duplicates = df[~df.duplicated()]

print(df_no_duplicates)

输出:

id     name  age
0   1    Alice   25
1   2      Bob   30
3   3  Charlie   35
4   4    David   40
6   5      Eve   45
  • 解释~df.duplicated() 返回的是 duplicated() 布尔 Series 的反向值,~TrueFalse~FalseTrue,因此通过 df[~df.duplicated()] 可以保留第一次出现的记录,删除后续的重复行。
示例 6:修改原始 DataFrame(使用 inplace=True
df.drop_duplicates(inplace=True)

print(df)
  • 解释drop_duplicates() 会修改原始的 DataFrame,删除重复行。

总结:

  • duplicated() 方法用于标记重复行,返回一个布尔值 Series,表示哪些行是重复的。

  • keep
    

    参数可以控制保留哪一条记录:

    • 'first'(默认):标记除了第一次出现的记录外,其他重复行。
    • 'last':标记除了最后一次出现的记录外,其他重复行。
    • False:标记所有重复的行,包括第一次和最后一次出现的行。
  • subset 参数允许你只根据特定的列来判断重复项。

  • 结合 duplicated() 和布尔索引,可以删除重复的行。

drop_duplicates()

Pandas 中,drop_duplicates() 是一个非常实用的函数,用于去除重复的行(或列)。它允许你根据特定的列或整个数据框来删除重复项。

drop_duplicates() 方法的基本用法:

DataFrame.drop_duplicates(subset=None, keep='first', inplace=False, ignore_index=False)

参数说明:

  • subset:指定哪些列用于判断重复。如果没有指定,默认情况下会根据所有列判断重复。

  • keep

    :决定保留哪一条重复记录:

    • 'first'(默认):保留首次出现的记录,删除后续的重复项。
    • 'last':保留最后一条记录,删除之前的重复项。
    • False:删除所有重复项。
  • inplace:是否在原始数据上进行修改。如果为 True,则会直接修改原始 DataFrame,并返回 None;如果为 False(默认),则返回一个新的 DataFrame

  • ignore_index:是否重新索引。默认为 False,如果为 True,则会重新排列索引。

例子:

假设有一个包含重复数据的 DataFrame

import pandas as pd

# 示例数据
data = {
    'id': [1, 2, 2, 3, 4, 4, 5],
    'name': ['Alice', 'Bob', 'Bob', 'Charlie', 'David', 'David', 'Eve'],
    'age': [25, 30, 30, 35, 40, 40, 45]
}

df = pd.DataFrame(data)

print(df)

输出:

   id     name  age
0   1    Alice   25
1   2      Bob   30
2   2      Bob   30
3   3  Charlie   35
4   4    David   40
5   4    David   40
6   5      Eve   45
示例 1:去除所有重复的行(基于所有列)
df_no_duplicates = df.drop_duplicates()

print(df_no_duplicates)

输出:

id     name  age
0   1    Alice   25
1   2      Bob   30
3   3  Charlie   35
4   4    David   40
6   5      Eve   45
  • 解释:默认情况下,drop_duplicates() 会检查所有列的重复项,并删除后面的重复行,只保留第一条出现的记录。
示例 2:根据某一列去重(例如:根据 id 列)
df_no_duplicates = df.drop_duplicates(subset=['id'])

print(df_no_duplicates)

输出:

id     name  age
0   1    Alice   25
1   2      Bob   30
3   3  Charlie   35
4   4    David   40
6   5      Eve   45
  • 解释subset=['id'] 表示根据 id 列来检查重复项。重复的 id=2id=4 被删除,只保留每个 id 的第一次出现。
示例 3:保留最后一次出现的重复记录
df_no_duplicates = df.drop_duplicates(subset=['id'], keep='last')

print(df_no_duplicates)

输出:

id     name  age
0   1    Alice   25
2   2      Bob   30
3   3  Charlie   35
5   4    David   40
6   5      Eve   45
  • 解释:通过 keep='last',我们选择保留重复项中最后一次出现的记录。
示例 4:删除所有重复的行(不保留任何重复项)
df_no_duplicates = df.drop_duplicates(subset=['id'], keep=False)

print(df_no_duplicates)

输出:

id     name  age
0   1    Alice   25
3   3  Charlie   35
6   5      Eve   45
  • 解释keep=False 表示删除所有重复的记录,包括第一次出现的记录。因此,只有没有重复的行被保留下来。
示例 5:修改原始 DataFrame(使用 inplace=True

511. 游戏玩法分析 I

176. 第二高的薪水

177. 第N高的薪水

df.drop_duplicates(subset=['id'], keep='first', inplace=True)

print(df)

输出:

id     name  age
0   1    Alice   25
1   2      Bob   30
3   3  Charlie   35
4   4    David   40
6   5      Eve   45
  • 解释:使用 inplace=True 后,drop_duplicates() 会直接在原始 df 上进行修改,而不是返回一个新的 DataFrame
示例 6:重新索引
df_no_duplicates = df.drop_duplicates(subset=['id'], keep='first', ignore_index=True)

print(df_no_duplicates)

输出:

id     name  age
0   1    Alice   25
1   2      Bob   30
2   3  Charlie   35
3   4    David   40
4   5      Eve   45
  • 解释:使用 ignore_index=True 后,删除重复行后会重新排列索引,从 0 开始。

总结:

  • drop_duplicates() 是一个非常实用的方法,可以帮助你快速清理重复的数据。
  • subset 参数允许你根据指定的列来判断是否为重复数据。
  • keep 参数控制保留哪一条记录:'first'(默认)、'last'False(删除所有重复项)。
  • 使用 inplace=True 可以直接修改原始 DataFrame,而不是返回一个新的 DataFrame

数据融合/拼接

merge()

关键字

  1. left:第一个 DataFrame 对象。

  2. right:第二个 DataFrame 对象。

  3. how:指定合并的方式。默认为 ‘inner’。其他选项包括 ‘left’, ‘right’, ‘outer’。

    • ‘inner’:内连接,只返回两个对象中都存在的键的交集。

    • ‘left’:左连接,返回左对象中的所有键,以及右对象中匹配的键。

      175. 组合两个表

    • ‘right’:右连接,返回右对象中的所有键,以及左对象中匹配的键。

    • ‘outer’:外连接,返回左和右对象中所有的键,匹配不到的键则填充 NaN。

  4. on:要加入的列名。必须在左右 DataFrame 对象中都存在。如果未指定,且未指定 left_onright_on,则 DataFrame 中的列名交集将被作为连接键。

  5. left_on:左 DataFrame 中的列或索引级别名称用作键。可以是列名、索引名或长度的数组。

    181. 超过经理收入的员工

  6. right_on:右 DataFrame 中的列或索引级别名称用作键。可以是列名、索引名或长度的数组。

  7. left_index:布尔值,默认为 False。如果为 True,则使用左 DataFrame 的索引(行标签)作为其连接键。

  8. right_index:布尔值,默认为 False。如果为 True,则使用右 DataFrame 的索引(行标签)作为其连接键。

  9. sort:布尔值,默认为 False。根据连接键对合并后的数据进行排序。这在合并具有大量数据的大型 DataFrame 时可能会非常耗时。

  10. suffixes:用于追加到重叠列名末尾的元组字符串(默认为 (‘_x’, ‘_y’))。例如,如果两个对象都有 ‘A’ 列,则结果对象将有 ‘A_x’ 和 ‘A_y’ 列。

  11. copy:布尔值,默认为 True。如果为 False,则不复制数据(可能节省内存)。

  12. indicator:布尔值或字符串,默认为 False。如果为 True 或字符串,将向输出 DataFrame 添加一个特殊列 ‘_merge’,以指示每行数据的来源:‘left_only’、‘right_only’ 或 ‘both’。如果为字符串,则将该字符串用作列名。

  13. validate:检查合并键是否在左右 DataFrame 对象中指定为列名。可以是 ‘one_to_one’, ‘one_to_many’, ‘many_to_one’, ‘many_to_many’ 之一。仅在合并键在 DataFrame 中明确指定时才有意义(即使用 onleft_onright_on 参数)。

示例1:内连接(Inner Join)

import pandas as pd
 
# 创建两个示例DataFrame
df1 = pd.DataFrame({
    'key': ['A', 'B', 'C', 'D'],
    'value1': [1, 2, 3, 4]
})
 
df2 = pd.DataFrame({
    'key': ['A', 'B', 'E', 'F'],
    'value2': [5, 6, 7, 8]
})
 
# 内连接
merged_inner = pd.merge(df1, df2, on='key', how='inner')
print(merged_inner)

输出:

key  value1  value2
0   A       1       5
1   B       2       6

示例2:左连接(Left Join)

577. 员工奖金

# 左连接
merged_left = pd.merge(df1, df2, on='key', how='left')
print(merged_left)

输出:

key  value1  value2
0   A       1     5.0
1   B       2     6.0
2   C       3     NaN
3   D       4     NaN

示例3:右连接(Right Join)

# 右连接
merged_right = pd.merge(df1, df2, on='key', how='right')
print(merged_right)

输出:

key  value1  value2
0   A     1.0       5
1   B     2.0       6
2   E     NaN       7
3   F     NaN       8

示例4:外连接(Outer Join)

# 外连接
merged_outer = pd.merge(df1, df2, on='key', how='outer')
print(merged_outer)

输出:

key  value1  value2
0   A     1.0     5.0
1   B     2.0     6.0
2   C     3.0     NaN
3   D     4.0     NaN
4   E     NaN     7.0
5   F     NaN     8.0

示例5:使用left_on和right_on参数

# 创建两个示例DataFrame,其中用于合并的列名不同
df3 = pd.DataFrame({
    'lkey': ['A', 'B', 'C'],
    'lvalue': [10, 20, 30]
})
 
df4 = pd.DataFrame({
    'rkey': ['A', 'B', 'D'],
    'rvalue': [40, 50, 60]
})
 
# 使用left_on和right_on参数进行合并
merged_custom_keys = pd.merge(df3, df4, left_on='lkey', right_on='rkey', how='inner')
print(merged_custom_keys)

输出:

lkey  lvalue rkey  rvalue
0    A      10    A      40
1    B      20    B      50

示例6:使用suffixes参数

# 创建两个示例DataFrame,其中有一列名称相同
df5 = pd.DataFrame({
    'key': ['X', 'Y', 'Z'],
    'value': [100, 200, 300]
})
 
df6 = pd.DataFrame({
    'key': ['X', 'Y', 'W'],
    'value': [400, 500, 600]
})
 
# 使用suffixes参数为相同名称的列添加后缀
merged_suffixes = pd.merge(df5, df6, on='key', suffixes=('_left', '_right'), how='inner')
print(merged_suffixes)

输出:

key  value_left  value_right
0   X         100          400
1   Y         200          500

这些示例展示了如何使用pandas.merge()函数进行不同类型的数据合并,包括内连接、左连接、右连接、外连接,以及如何处理不同名称的合并键和相同名称的列。

concat()

在Pandas中,concat函数是一个非常强大的工具,用于将多个pandas对象(如DataFrame或Series)沿着指定轴拼接在一起。这个函数非常灵活,允许你沿着行(axis=0,默认)或列(axis=1)进行拼接,并且可以通过多种方式处理索引和列标签。

以下是pd.concat函数的一些关键参数和用法示例:

关键参数

  • objs:要拼接的对象列表或字典。列表中的元素可以是DataFrame、Series或其他pandas对象。如果是字典,则字典的键会被用作结果的列名或行索引。
  • axis:拼接的轴。0表示沿着行拼接(纵向),1表示沿着列拼接(横向)。默认值为0。
  • join:指定如何处理索引。‘outer’(默认)表示取并集,'inner’表示取交集。
  • ignore_index:如果为True,则不保留原有的索引,而是生成一个新的整数索引。
  • keys:用于添加多级索引(层次化索引)。这个参数通常与字典一起使用。
  • levels:用于多级索引(层次化索引)的级别名称。
  • names:多级索引(层次化索引)的名称。
  • verify_integrity:如果为True,则在拼接时检查新生成的DataFrame的索引/列是否有重复。这有助于捕捉潜在的错误。

用法示例

1. 沿着行拼接两个DataFrame
import pandas as pd
 
df1 = pd.DataFrame({'A': ['A0', 'A1'], 'B': ['B0', 'B1']})
df2 = pd.DataFrame({'A': ['A2', 'A3'], 'B': ['B2', 'B3']})
 
result = pd.concat([df1, df2], axis=0)
print(result)
2. 沿着列拼接两个DataFrame
df1 = pd.DataFrame({'A': ['A0', 'A1'], 'B': ['B0', 'B1']})
df2 = pd.DataFrame({'C': ['C0', 'C1'], 'D': ['D0', 'D1']})
 
result = pd.concat([df1, df2], axis=1)
print(result)
3. 使用字典拼接,并添加多级索引
df1 = pd.DataFrame({'A': ['A0', 'A1'], 'B': ['B0', 'B1']})
df2 = pd.DataFrame({'A': ['A2', 'A3'], 'B': ['B2', 'B3']})
 
result = pd.concat({'key1': df1, 'key2': df2}, axis=0, keys=['group1', 'group2'])
print(result)

在这个例子中,我们使用了keys参数来添加一个新的层次化索引,使得结果DataFrame有两个索引级别:一个是我们指定的键(‘group1’和’group2’),另一个是原有的索引。

4. 忽略原有索引,生成新的整数索引
df1 = pd.DataFrame({'A': ['A0', 'A1'], 'B': ['B0', 'B1']}, index=[1, 2])
df2 = pd.DataFrame({'A': ['A2', 'A3'], 'B': ['B2', 'B3']}, index=[3, 4])
 
result = pd.concat([df1, df2], axis=0, ignore_index=True)
print(result)

在这个例子中,ignore_index=True使得结果DataFrame使用了新的从0开始的整数索引。

顺序错乱值

sort_values()

pandas中,sort_values()是一个用于对DataFrameSeries按指定列进行排序的方法。它允许你按升序或降序排列数据。

用法

DataFrame.sort_values(by, axis=0, ascending=True, inplace=False, kind='quicksort', na_position='last', ignore_index=False)

参数说明

  • by: 用于排序的列名称或列名的列表。对于DataFrame,这是你希望依据其值来排序的列。
  • axis: 默认值为0,表示按行排序。如果为1,表示按列排序。
  • ascending: 布尔值或布尔值列表,默认为True,表示按升序排序。如果为False,则按降序排序。如果是一个列表,长度应与by的长度相同,用于不同列的排序顺序。
  • inplace: 默认为False,表示返回一个新的排序后的DataFrame,如果设为True,则原地修改,不返回新对象。
  • kind: 排序算法,支持'quicksort'(快速排序)、'mergesort'(归并排序)和'heapsort'(堆排序)。默认为'quicksort'
  • na_position: 默认为'last',表示缺失值排在最后。如果设为'first',缺失值将排在最前面。
  • ignore_index: 默认为False,表示保留原来的索引。如果设为True,返回排序后的结果时,重新生成索引。

示例

176. 第二高的薪水

177. 第N高的薪水

620. 有趣的电影

1. 按单列排序
import pandas as pd

df = pd.DataFrame({
    'A': [3, 1, 4, 2],
    'B': [7, 8, 5, 6]
})

# 按列 'A' 升序排序
df_sorted = df.sort_values(by='A')
print(df_sorted)

输出:

   A  B
1  1  8
3  2  6
0  3  7
2  4  5
2. 按多列排序
# 按 'A' 升序,'B' 降序排序
df_sorted = df.sort_values(by=['A', 'B'], ascending=[True, False])
print(df_sorted)

输出:

   A  B
1  1  8
3  2  6
0  3  7
2  4  5
3. 原地排序(不返回新的DataFrame
df.sort_values(by='A', inplace=True)
print(df)

输出:

   A  B
1  1  8
3  2  6
0  3  7
2  4  5
4. 排序时处理缺失值
df_with_nan = pd.DataFrame({
    'A': [3, 1, 4, None],
    'B': [7, 8, None, 6]
})

# 按 'A' 升序排序,缺失值排在最后
df_sorted = df_with_nan.sort_values(by='A', na_position='last')
print(df_sorted)

输出:

	A    B
1  1.0  8.0
0  3.0  7.0
2  4.0  NaN
3  NaN  6.0

注意

  • sort_values()是对数据进行排序并返回排序后的数据,而不改变原始的DataFrame(除非inplace=True)。
  • 对于Seriessort_values()可以直接作用在数据上。

sort_index()

pandas中,sort_index()是一个用于根据行或列的索引对DataFrameSeries进行排序的方法。它的主要作用是按照索引的顺序对数据进行排序,而不是按照数据的值进行排序。

用法

DataFrame.sort_index(axis=0, ascending=True, inplace=False, kind='quicksort', na_position='last', ignore_index=False)

参数说明

  • axis: 默认为0,表示按照行索引进行排序。如果为1,则表示按列索引排序。
  • ascending: 布尔值或布尔值列表,默认True。表示是否按升序排序。如果为False,则按降序排序。如果是一个列表,长度应该和索引的数量一致,用于不同索引的排序顺序。
  • inplace: 默认为False,表示返回一个排序后的DataFrame。如果设为True,则对原始数据进行排序,不返回新对象。
  • kind: 排序算法,支持'quicksort'(快速排序)、'mergesort'(归并排序)和'heapsort'(堆排序)。默认为'quicksort'
  • na_position: 默认为'last',表示缺失值排在最后。如果设为'first',缺失值会排在最前面。
  • ignore_index: 默认为False,表示保留原有的索引。如果设为True,会重新生成索引。

示例

1. 按行索引排序
import pandas as pd

df = pd.DataFrame({
    'A': [3, 1, 4, 2],
    'B': [7, 8, 5, 6]
}, index=['d', 'a', 'c', 'b'])

# 按行索引升序排序
df_sorted = df.sort_index()
print(df_sorted)

输出:

   A  B
a  1  8
b  2  6
c  4  5
d  3  7
2. 按列索引排序
# 按列索引升序排序
df_sorted = df.sort_index(axis=1)
print(df_sorted)

输出:

   A  B
d  3  7
a  1  8
c  4  5
b  2  6
3. 降序排序索引
# 按行索引降序排序
df_sorted = df.sort_index(ascending=False)
print(df_sorted)

输出:

   A  B
d  3  7
c  4  5
b  2  6
a  1  8
4. 原地排序(不返回新的DataFrame
df.sort_index(inplace=True)
print(df)

输出:

   A  B
a  1  8
b  2  6
c  4  5
d  3  7
5. 排序时处理缺失值
df_with_nan = pd.DataFrame({
    'A': [3, 1, 4, None],
    'B': [7, 8, None, 6]
}, index=['d', 'a', 'c', 'b'])

# 按行索引排序,并将缺失值放到最后
df_sorted = df_with_nan.sort_index(na_position='last')
print(df_sorted)

输出:

     A    B
a  1.0  8.0
b  NaN  6.0
c  4.0  NaN
d  3.0  7.0
6. 忽略原有索引,重新生成索引
# 忽略原有索引,重新生成索引
df_sorted = df_with_nan.sort_index(ignore_index=True)
print(df_sorted)

输出:

     A    B
0  1.0  8.0
1  NaN  6.0
2  4.0  NaN
3  3.0  7.0

总结

  • sort_index() 主要是根据索引进行排序,而不是根据数据本身的值。
  • 可以选择按行索引或列索引进行排序,支持升序和降序排列。
  • 通过设置inplace=True,可以原地修改DataFrame
  • 处理缺失值时,可以使用na_position来决定缺失值的位置。

rank()

pandas 中,rank() 方法用于对 DataFrameSeries 中的数值进行排名。根据所提供的参数,可以控制排名的计算方式,支持多种排名方法,如 升序降序,以及 相同值的排名 方式。

基本用法

DataFrame.rank(axis=0, method='average', ascending=True, na_option='keep', numeric_only=False, pct=False)

参数解释

  • axis: 默认为 0,表示对行进行排名。如果为 1,则对列进行排名。

  • method
    排名方法。可选值有:
    • 'average': 相同数值的平均排名(默认)。
    • 'min': 相同数值的最小排名。
    • 'max': 相同数值的最大排名。
    • 'first': 按照原始顺序进行排名,遇到相同数值时,先出现的排前面。
    • 'dense': 稠密排名,相同数值的排名相同,接下来的排名没有空缺。
  • ascending: 布尔值,默认为 True,表示升序排序。如果为 False,则按降序排序。

  • na_option: 控制缺失值的处理方式。可选值为 'keep''top''bottom'。默认为 'keep',即保留缺失值不参与排名。 'top''bottom' 分别表示将缺失值排在前面或最后。

  • numeric_only: 默认为 False,表示包括所有类型的列进行排名。如果为 True,则仅考虑数值类型的列。

  • pct: 默认为 False,表示返回的排名为整数。如果为 True,返回的排名是比例值(百分比形式)。

示例

1. 基本排名(默认 average
import pandas as pd

data = {'score': [3.5, 4.0, 3.65, 3.85, 4.0, 3.65]}
df = pd.DataFrame(data)

df['rank'] = df['score'].rank()
print(df)

输出:

   score  rank
0   3.50   4.0
1   4.00   1.5
2   3.65   3.5
3   3.85   2.0
4   4.00   1.5
5   3.65   3.5

解释

  • 使用 average 排名方法,相同的分数(如 4.0 和 3.65)的排名为相同的平均值。例如,4.0 出现了两次,所以它们的排名是 1.5
2. 使用 min 排名方法

1070. 产品销售分析 III

df['rank_min'] = df['score'].rank(method='min')
print(df)

输出:

   score  rank  rank_min
0   3.50   4.0       4.0
1   4.00   1.5       1.0
2   3.65   3.5       3.0
3   3.85   2.0       2.0
4   4.00   1.5       1.0
5   3.65   3.5       3.0

解释

  • 使用 min 方法时,所有相同的分数都获得最小排名。例如,4.0 的排名是 1,3.65 的排名是 3,即便它们出现多次。
3. 使用 dense 排名方法

178. 分数排名

df['rank_dense'] = df['score'].rank(method='dense')
print(df)

输出:

   score  rank  rank_min  rank_dense
0   3.50   4.0       4.0         4.0
1   4.00   1.5       1.0         1.0
2   3.65   3.5       3.0         3.0
3   3.85   2.0       2.0         2.0
4   4.00   1.5       1.0         1.0
5   3.65   3.5       3.0         3.0

解释

  • dense 方法给相同的分数相同的排名,并且排名没有跳跃。例如,两个分数相同(如 4.0 和 3.65)的排名相同,但接下来的排名没有空缺。
4. 排名方法 first
df['rank_first'] = df['score'].rank(method='first')
print(df)

输出:

   score  rank  rank_min  rank_dense  rank_first
0   3.50   4.0       4.0         4.0         4.0
1   4.00   1.5       1.0         1.0         1.0
2   3.65   3.5       3.0         3.0         3.0
3   3.85   2.0       2.0         2.0         2.0
4   4.00   1.5       1.0         1.0         1.0
5   3.65   3.5       3.0         3.0         3.0

解释

  • first 方法按照出现的顺序进行排名。当有相同分数时,先出现的分数获得较小的排名。
5. 排名计算百分比(pct=True
df['rank_pct'] = df['score'].rank(pct=True)
print(df)

输出:

   score  rank  rank_min  rank_dense  rank_first  rank_pct
0   3.50   4.0       4.0         4.0         4.0   0.833333
1   4.00   1.5       1.0         1.0         1.0   0.166667
2   3.65   3.5       3.0         3.0         3.0   0.5
3   3.85   2.0       2.0         2.0         2.0   0.333333
4   4.00   1.5       1.0         1.0         1.0   0.166667
5   3.65   3.5       3.0         3.0         3.0   0.5

解释

  • pct=True 返回百分比排名,即每个分数的排名占所有分数的比例。排名越高的分数比例越小,接近 0。

总结

  • rank() 是一个非常灵活的工具,用于根据不同的规则为数据中的每个元素分配排名。
  • 常见的排名方法包括 average(默认)、minmaxdensefirst,它们决定了相同值的排名如何计算。
  • 可以通过设置 ascending=False 来进行降序排名,pct=True 返回排名的百分比。

数据的移动

shift()

shift() 函数是 Pandas 库中的一个数据处理函数,用于将数据按指定方向移动或偏移。它可以对时间序列数据或其他类型的数据进行操作,通常用于计算时间序列数据的差值、百分比变化等。该函数的主要作用是将数据移动到指定的行或列,留下空白或填充 NaN 值。

shift() 函数的语法
shift() 函数的基本语法如下:

DataFrame.shift(periods=1, freq=None, axis=0, fill_value=None)
参数说明:

  • periods:指定移动的步数,可以为正数(向下移动)或负数(向上移动)。默认为 1。

  • freq:可选参数,用于指定时间序列数据的频率,通常用于时间序列数据的移动操作。

  • axis:指定移动的方向,可以为 0(默认,沿行移动)或 1(沿列移动)。

  • fill_value:可选参数,用于填充移动后留下的空白位置,通常为填充 NaN 值。

shift() 函数的示例
通过一些示例来演示 shift() 函数的用法。

示例 1:向下移动数据

import pandas as pd

data = {'A': [1, 2, 3, 4, 5],
        'B': [10, 20, 30, 40, 50]}
df = pd.DataFrame(data)

向下移动一行数据

197. 上升的温度

df_shifted = df.shift(periods=1)
print(df_shifted)
输出结果:

A     B
 0  NaN   NaN
1  1.0  10.0
2  2.0  20.0
3  3.0  30.0
4  4.0  40.0

在这个示例中,创建了一个包含两列数据的 DataFrame,并使用 shift() 函数向下移动了一行数据。移动后,第一行的数据被填充为 NaN。

示例 2:向上移动数据

import pandas as pd

data = {'A': [1, 2, 3, 4, 5],
        'B': [10, 20, 30, 40, 50]}
df = pd.DataFrame(data)

向上移动一行数据

df_shifted = df.shift(periods=-1)
print(df_shifted)
输出结果:
    
    A     B
0  2.0  20.0
1  3.0  30.0
2  4.0  40.0
3  5.0  50.0
4  NaN   NaN

这个示例,使用负数的 periods 参数将数据向上移动了一行。最后一行的数据被填充为 NaN。

示例 3:向右移动列数据

import pandas as pd

data = {'A': [1, 2, 3, 4, 5],
        'B': [10, 20, 30, 40, 50]}
df = pd.DataFrame(data)

向右移动一列数据

 df_shifted = df.shift(periods=1, axis=1)
print(df_shifted)
输出结果:
 
 A     B
 0  NaN   1.0
1  NaN   2.0
2  NaN   3.0
3  NaN   4.0
4  NaN   5.0

在这个示例中,使用 axis=1 参数将列数据向右移动了一列,左边填充为 NaN。

示例 4:指定填充值

import pandas as pd

data = {'A': [1, 

2, 3, 4, 5],
        'B': [10, 20, 30, 40, 50]}
df = pd.DataFrame(data)

向下移动一行数据,填充空白处为 0

df_shifted = df.shift(periods=1, fill_value=0)
print(df_shifted)
输出结果:

   A   B
0  0   0
1  1  10
2  2  20
3  3  30
4  4  40

在这个示例中,使用 fill_value 参数指定了填充值为 0,因此移动后的空白位置被填充为 0。

日期类型应用

Timedelta()

pandas.TimedeltaPandas 库中的一个类,用于表示时间跨度或持续时间。它通常用于表示两个日期或时间之间的差异,或者进行日期、时间的加减运算。

Timedelta 的常见用途:

  1. 表示时间间隔:例如一天、两小时、三分钟等。
  2. 日期时间运算:例如,计算一个日期与另一个日期的差异,或者将某个时间单位添加到日期上。

Timedelta 组件:

  • days:天数。
  • hours:小时数。
  • minutes:分钟数。
  • seconds:秒数。
  • milliseconds:毫秒数。
  • microseconds:微秒数。
  • nanoseconds:纳秒数。

创建 Timedelta 对象:

你可以通过多种方式创建 Timedelta 对象:

import pandas as pd

# 通过字符串创建 Timedelta
timedelta1 = pd.Timedelta('1 days')  # 1 天
timedelta2 = pd.Timedelta('5 hours')  # 5 小时
timedelta3 = pd.Timedelta('2 minutes')  # 2 分钟

# 通过整数和单位创建 Timedelta
timedelta4 = pd.Timedelta(days=1)  # 1 天
timedelta5 = pd.Timedelta(hours=5)  # 5 小时
timedelta6 = pd.Timedelta(minutes=10)  # 10 分钟

# 通过多个单位创建 Timedelta
timedelta7 = pd.Timedelta(weeks=1, days=2, hours=3, minutes=4)  # 1 周 2 天 3 小时 4 分钟

Timedelta 的常见操作:

加减时间

197. 上升的温度

你可以将 Timedelta 对象加到一个 datetime 对象上,或者从中减去。

# 当前时间
now = pd.to_datetime('2024-01-01')

# 加 5 天
new_date = now + pd.Timedelta(days=5)
print(new_date)  # 输出:2024-01-06

# 减 2 小时
new_time = now - pd.Timedelta(hours=2)
print(new_time)  # 输出:2023-12-31 22:00:00
计算两个日期或时间之间的差异

你可以通过直接相减两个 datetime 对象来计算时间差异,结果是一个 Timedelta 对象。

# 两个时间
date1 = pd.to_datetime('2024-01-01')
date2 = pd.to_datetime('2024-01-06')

# 计算差异
timedelta = date2 - date1
print(timedelta)  # 输出:5 days 00:00:00
Timedelta 对象进行运算
# 创建一个 Timedelta 对象
delta = pd.Timedelta(days=2, hours=3)

# 输出 Timedelta 对象的各个部分
print(delta.days)  # 2
print(delta.seconds)  # 10800 秒(3 小时 = 3 * 3600 秒)
print(delta.total_seconds())  # 177600 秒 (2 天 3 小时的总秒数)

示例:用 Timedelta 计算前一天日期

如果你想利用 Timedelta 来比较日期并确保日期是连续的(例如,确保没有跳过的日期),你可以用 Timedelta 来加减日期,确保前后日期是连续的。

例如,假设你有一个日期列,并希望找出温度比前一天高的记录。

示例代码:

import pandas as pd

# 示例数据
data = {
    'id': [1, 2],
    'recordDate': ['2000-12-14', '2000-12-16'],
    'temperature': [3, 5]
}

# 创建 DataFrame
df = pd.DataFrame(data)

# 将 'recordDate' 列转换为日期格式并排序
df['recordDate'] = pd.to_datetime(df['recordDate'])
df = df.sort_values('recordDate')

# 获取前一天的温度
df['previous_temperature'] = df['temperature'].shift(1)
df['previous_recordDate'] = df['recordDate'].shift(1)

# 使用 Timedelta 来检查日期是否是前一天
df['is_previous_day'] = df['recordDate'] == (df['previous_recordDate'] + pd.Timedelta(days=1))

# 筛选出温度比前一天高的记录,且日期是连续的(前后日期相差 1 天)
result = df[(df['temperature'] > df['previous_temperature']) & df['is_previous_day']]['id']

# 输出结果
print(result)

解释:

  1. 日期转换:将 recordDate 列转换为日期格式,并按日期排序。
  2. 前一天比较:通过 shift(1) 获取前一天的日期和温度。
  3. 日期差检查:用 pd.Timedelta(days=1) 确保前一天的日期是连续的。
  4. 筛选符合条件的结果:确保温度比前一天高,并且日期是连续的。

输出结果:

less



Series([], Name: id, dtype: int64)

解释:

由于 2000-12-142000-12-16 之间没有 2000-12-15,所以没有连续的日期,最终返回空结果。

总结:

  • Timedelta 主要用于表示时间差,支持加减运算,并可以方便地进行日期时间之间的比较和计算。
  • 在日期比较时,Timedelta 可以帮助我们确保前后日期是连续的,从而避免出现日期跳跃的问题。

DateOffset()

550. 游戏玩法分析 IV

DateOffset是pandas库中用于处理日期时间偏移量的类。它允许你以不同的时间单位(如天、小时、分钟等)来移动日期时间。

特点

  • 支持多种时间单位:天、小时、分钟等。
  • 遵循日历规则,适用于处理如工作日、月末等复杂偏移。

使用方法

  1. 创建一个DateOffset对象,指定偏移的时间单位和数量。
  2. 将DateOffset对象与日期时间相加或相减,实现偏移。

示例

import pandas as pd
 
# 创建一个日期
date = pd.Timestamp('2023-01-01')
 
# 创建一个DateOffset对象,表示一天的偏移
offset = pd.DateOffset(days=1)
 
# 应用偏移
new_date = date + offset
 
print(new_date)  # 输出:2023-01-02 00:00:00

注意事项

  • 确保时间单位与DateOffset对象的参数相匹配。
  • 处理时区信息时,确保时区正确处理。

frame类型数据更新

pandas 中将一条数据更新到一个 DataFrame 中,可以有几种不同的方法,取决于你是要 添加新行 还是 更新已有行

方法 1: 添加新行

如果你想将一条新数据(新行)添加到 DataFrame 中,可以使用 pd.DataFrame.append()pd.concat() 方法。这两种方法都可以用来将新的数据添加到现有的 DataFrame 中。

示例 1: 使用 append()

假设你有一个现有的 DataFrame 和你要添加的一行数据:

import pandas as pd

# 示例 DataFrame
df = pd.DataFrame({
    'id': [1, 2, 3],
    'num': ['A', 'B', 'C']
})

# 要插入的新行
new_row = {'id': 4, 'num': 'D'}

# 使用 append() 添加新行
df = df.append(new_row, ignore_index=True)

# 打印结果
print(df)

输出:

   id num
0   1   A
1   2   B
2   3   C
3   4   D

说明:

  • append() 方法会返回一个新的 DataFrame,所以需要将返回结果重新赋值给 df
  • ignore_index=True 表示重新生成索引。
示例 2: 使用 concat()

concat() 是一种更灵活的方法,也可以用于添加新行。我们可以通过将新的数据转换为一个单行的 DataFrame 并与原 DataFrame 合并来实现。

# 将新行转换为 DataFrame
new_row_df = pd.DataFrame({'id': [4], 'num': ['D']})

# 使用 concat() 添加新行
df = pd.concat([df, new_row_df], ignore_index=True)

# 打印结果
print(df)

输出:

   id num
0   1   A
1   2   B
2   3   C
3   4   D

方法 2: 更新已有行

如果你要根据某些条件来更新 DataFrame 中的已有行数据,可以直接通过行索引进行更新。例如,假设我们想更新 id 为 2 的行的 num 值。

示例 3: 更新已有行的数据
# 假设我们要更新 id 为 2 的行
df.loc[df['id'] == 2, 'num'] = 'Updated Value'

# 打印结果
print(df)

输出:

   id            num
0   1              A
1   2  Updated Value
2   3              C
3   4              D

说明:

  • df.loc[df['id'] == 2, 'num'] 用于选择 id 为 2 的行的 num 列,然后直接将其值更新为 'Updated Value'

方法 3: 通过索引位置更新

如果你知道要更新的数据行的索引,可以直接通过 iloc[] 来访问并更新该行。

示例 4: 通过索引位置更新数据
# 假设我们要更新索引为 1 的行
df.iloc[1, df.columns.get_loc('num')] = 'Updated Again'

# 打印结果
print(df)

输出:

   id            num
0   1              A
1   2  Updated Again
2   3              C
3   4              D

方法 4: 批量更新

如果你需要根据某些条件批量更新多行数据,可以使用 apply()where() 等方法。

示例 5: 使用 apply() 批量更新

# 假设我们根据 'id' 列的值来更新 'num' 列
df['num'] = df['id'].apply(lambda x: 'Updated' if x == 2 else 'Not Updated')

# 打印结果
print(df)

输出:

   id         num
0   1  Not Updated
1   2     Updated
2   3  Not Updated
3   4  Not Updated

示例 6: 使用 update() 批量更新

DataFrame.update() 方法的作用是用另一个 DataFrameSeries 来更新当前 DataFrame 中的值。更新时,源数据(other)的索引和列索引会与目标数据进行对比,如果匹配,则更新目标数据的对应位置。

update() 方法的参数
  • other:另一个 DataFrameSeries,用于提供要更新的值。

  • join控制如何对齐索引和列。可以是 'left''right''outer''inner',默认是 'left'

    'left':使用 other 中的索引和列进行更新(保留目标 DataFrame 的索引和列)。

    'right':使用目标 DataFrame 中的索引和列进行更新。

    'outer':合并两个 DataFrame 的所有索引和列,任何一个 DataFrame 中缺失的部分将填充 NaN

    'inner':只使用两个 DataFrame 中都有的索引和列。

  • overwrite:布尔值,默认是 True。如果为 True,则将目标 DataFrame 中的所有值都更新为源 DataFrame 中的对应值。否则,只会更新那些原数据中为 NaN 的位置。

update() 示例
示例 1:基本使用
import pandas as pd

# 原始 DataFrame
df1 = pd.DataFrame({
    'A': [1, 2, 3, 4],
    'B': [5, 6, 7, 8],
    'C': [9, 10, 11, 12]
})

# 更新数据的 DataFrame
df2 = pd.DataFrame({
    'A': [10, 20],
    'B': [50, 60],
    'C': [15, 25]
}, index=[1, 2])

# 使用 update() 更新 df1
df1.update(df2)

print(df1)

输出:

    A   B   C
0   1   5   9
1  20  50  15
2  20  60  25
3   4   8  12

说明:

  • df1 中,索引为 1 和 2 的行被 df2 中相应的值替换了。
  • df1 中其他位置的值(如索引为 0 和 3 的行)没有被 df2 中的任何值更新,因为 df2 中没有这些位置的数据。
示例 2:使用 join 参数

通过 join 参数,可以控制如何对齐索引和列。如果 join='left',那么将保留 df1 的索引,并使用 df2 中的值进行更新。

df1.update(df2, join='left')
print(df1)

输出:

    A   B   C
0   1   5   9
1  20  50  15
2  20  60  25
3   4   8  12
示例 3:使用 overwrite=False

如果你不希望更新已经存在值的单元格,而只更新 NaN 值,可以将 overwrite=False

df1 = pd.DataFrame({
    'A': [1, 2, 3, 4],
    'B': [5, 6, 7, 8],
    'C': [None, 10, None, 12]
})

df2 = pd.DataFrame({
    'A': [10, 20],
    'B': [50, 60],
    'C': [15, 25]
}, index=[1, 2])

# 使用 update() 更新 df1,但不覆盖已存在的非 NaN 值
df1.update(df2, overwrite=False)

print(df1)

输出:

    A   B     C
0   1   5   NaN
1  20  50  15.0
2  20  60  25.0
3   4   8  12.0

说明:

  • 由于 overwrite=Falsedf1 中已有的 NaN 值(例如 A[0]C[0])被更新,而已存在的非 NaN 值(例如 C[3])没有被替换。
示例 4:update()join='outer' 使用
df1 = pd.DataFrame({
    'A': [1, 2],
    'B': [3, 4]
}, index=[0, 1])

df2 = pd.DataFrame({
    'A': [5, 6],
    'C': [7, 8]
}, index=[1, 2])

# 使用 'outer' join,合并 df1 和 df2 的所有索引和列
df1.update(df2, join='outer')

print(df1)

输出:

     A    B    C
0  1.0  3.0  NaN
1  6.0  4.0  8.0
2  NaN  NaN  7.0

说明:

  • 使用 join='outer' 时,df1 中所有索引和列都会与 df2 的索引和列合并。df2 中没有的值将填充为 NaN
update() 的优缺点

优点:

  • update() 方法直接修改原始 DataFrame,它不会创建新的 DataFrame,因此可以节省内存。
  • 可以灵活地控制更新行为,通过 joinoverwrite 参数,可以适应不同的需求。

缺点:

  • update() 仅会替换原始 DataFrame 中对应索引和列的部分。如果 df2 中的某些行列不在 df1 中,它们不会影响 df1
  • 无法直接应用复杂的自定义操作(如根据条件更新),这时可能需要用其他方法(如 apply())来实现。

总结

  • 添加新行:可以使用 append()concat() 方法。
  • 更新已有行:可以通过 loc[]iloc[] 进行条件更新或按索引位置更新。
  • 批量更新:使用 apply()where() 或其他条件逻辑进行批量更新。
  • **update()**方法主要用于根据另一个 DataFrame 更新当前 DataFrame,并且具有灵活的参数来控制如何处理索引和更新规则。

固定窗口移动

rolling()

# Pandas `rolling` 方法总结

`rolling` 是 Pandas 中用于进行滑动窗口操作的函数,可以用于时间序列数据的聚合、平滑等操作。常见的聚合操作包括均值、和、标准差等,还可以与其他函数结合使用以实现更复杂的计算。

## 1. 基本用法

通过 `rolling(window)` 创建一个滑动窗口,`window` 表示窗口大小。

### 示例:

```
import pandas as pd

data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9])

# 计算每个窗口的均值
rolling_mean = data.rolling(window=3).mean()

print(rolling_mean)

输出:

0    NaN
1    NaN
2    2.0
3    3.0
4    4.0
5    5.0
6    6.0
7    7.0
8    8.0
dtype: float64

常见的聚合操作

agg() 结合使用

agg() 允许在滑动窗口中使用多个聚合函数。

rolling_agg = data.rolling(window=3).agg(['sum', 'mean', 'std'])

apply() 结合使用

180. 连续出现的数字

apply() 可以对每个窗口应用自定义的函数。

rolling_apply = data.rolling(window=3).apply(lambda x: x.max() - x.min())

shift() 结合使用

shift() 用于计算窗口之间的差异,通常用于滞后比较。

rolling_mean = data.rolling(window=3).mean()
rolling_diff = rolling_mean - rolling_mean.shift(1)

min()max() 结合使用

min()max() 计算窗口内的最小值和最大值。

rolling_min = data.rolling(window=3).min()
rolling_max = data.rolling(window=3).max()

corr()cov() 结合使用

corr()cov() 用于计算两个时间序列之间的相关性或协方差。

rolling_corr = data1.rolling(window=3).corr(data2)

cum*() 结合使用

cummin()cummax()cumsum() 等方法用于计算窗口的累计统计量。

rolling_cumsum = data.rolling(window=3).cumsum()

expanding() 结合使用

expanding() 创建一个从数据开始到当前位置的滑动窗口,用于计算累计值。

expanding_sum = data.expanding().sum()

常用参数

  • window: 窗口大小,表示每个滑动窗口包含的数据量。
  • min_periods: 窗口内至少需要多少个有效数据才能进行计算,默认值为 None
  • center: 默认为 False,表示窗口右对齐。如果设置为 True,窗口会以当前数据点为中心进行计算。

示例:

rolling_data = data.rolling(window=3, min_periods=2).mean()

总结

rolling 是 Pandas 中一个非常强大的工具,能够方便地对时间序列数据进行窗口聚合计算。与其他函数结合使用时,rolling 可以帮助我们实现更复杂的分析任务,适用于金融、工程、科学等多个领域的数据处理。

常用的组合方法包括:

  • agg(): 多聚合函数应用。
  • apply(): 自定义计算。
  • shift(): 滞后操作。
  • min(), max(): 窗口的最小值、最大值。
  • corr(), cov(): 计算相关性和协方差。
  • cum*(): 累积统计。
  • expanding(): 扩展窗口的累计统计。

分组聚合

groupby()

586. 订单最多的客户

基本用法

  • 分组:通过指定一个或多个列名作为键来对数据进行分组。
  • 聚合:对每个分组应用聚合函数,如求和(sum())、平均值(mean())、最大值(max())、最小值(min())等。
  • 重置索引:分组操作会改变DataFrame的索引,通常你会想要使用 reset_index() 方法来重置索引,使其成为一个普通的列。

示例

单键分组
import pandas as pd
 
# 创建一个简单的DataFrame
df = pd.DataFrame({
    'Category': ['A', 'B', 'A', 'B', 'A'],
    'Values': [10, 20, 30, 40, 50]
})
 
# 根据'Category'列进行分组,并计算每个组的和
grouped = df.groupby('Category')['Values'].sum().reset_index()
 
print(grouped)

在这个例子中,数据被分为两组:‘A’ 和 ‘B’,然后计算了每个组的’Values’列的和。

多键分组

1050. 合作过至少三次的演员和导演

# 创建一个包含多个分类列的DataFrame
df_multi = pd.DataFrame({
    'Category1': ['X', 'X', 'Y', 'Y'],
    'Category2': ['A', 'B', 'A', 'B'],
    'Values': [1, 2, 3, 4]
})
 
# 根据'Category1'和'Category2'列进行分组,并计算每个组的和
grouped_multi = df_multi.groupby(['Category1', 'Category2'])['Values'].sum().reset_index()
 
print(grouped_multi)

在这个例子中,数据被分为四组:(‘X’, ‘A’)、(‘X’, ‘B’)、(‘Y’, ‘A’) 和 (‘Y’, ‘B’),然后计算了每个组的’Values’列的和。

应用多个聚合函数
# 使用agg方法应用多个聚合函数
grouped_agg = df.groupby('Category')['Values'].agg(['sum', 'mean', 'max', 'min']).reset_index()
 
print(grouped_agg)

在这个例子中,对每个分组应用了四个聚合函数:求和、平均值、最大值和最小值。

转换和过滤

除了聚合之外,groupby() 还可以与 transform() 方法结合使用来进行数据转换,或者与 filter() 方法结合使用来过滤数据。

# 使用transform方法计算每个组的平均值,并将其作为新列添加到原始DataFrame中
df['Mean'] = df.groupby('Category')['Values'].transform('mean')
 
print(df)

在这个例子中,每个组的’Values’列的平均值被计算出来,并作为新列’Mean’添加到了原始DataFrame中。

注意事项

  • 当使用 groupby() 时,确保你理解分组键和聚合函数如何影响你的数据。
  • 聚合操作会改变数据的形状,通常会导致某些行或列的丢失。
  • 如果你的DataFrame很大,groupby() 操作可能会比较耗时,特别是在多键分组或应用复杂聚合函数时。在这种情况下,考虑优化你的代码或使用更高效的数据处理策略。

transform()

184. 部门工资最高的员工

550. 游戏玩法分析 IV

transform用于对组内数据进行转换并返回与原始数据框形状相同的结果。它通常与groupby一起使用,目的是对每个组进行操作后,将结果“广播”到原始数据框中。基本用法如下:

# 对每个组计算'value'列的均值,并将均值返回到原数据框中
df['mean_value'] = df.groupby('group')['value'].transform('mean')
print(df)

结合使用

在实际使用中,groupbytransform可以结合起来,从而对数据进行强大的分组计算。例如,计算每个分组的标准差并将其填充到原数据框中:

# 计算每个组的标准差,并将结果赋给原数据框
df['std_value'] = df.groupby('group')['value'].transform('std')
print(df)

apply()

基本用法

  • 对列应用函数:默认情况下,apply() 方法会对DataFrame的每一列应用函数。如果你想对行应用函数,需要设置 axis=1
  • 返回值apply() 方法返回一个新的Series(如果沿着列应用)或DataFrame(如果沿着行应用,且函数返回多个值)。
  • 函数:你可以传递任何可调用对象(如函数、lambda表达式或方法)给 apply()

示例

对列应用函数

610. 判断三角形

import pandas as pd
 
# 创建一个简单的DataFrame
df = pd.DataFrame({
    'A': [1, 2, 3],
    'B': [4, 5, 6],
    'C': [7, 8, 9]
})
 
# 定义一个简单的函数,对每个元素加1
def add_one(x):
    return x + 1
 
# 对每一列应用add_one函数
df_plus_one = df.apply(add_one)
 
print(df_plus_one)

在这个例子中,add_one 函数被应用于DataFrame的每一列,每个元素都增加了1。

对行应用函数
# 定义一个函数,计算每行的和
def row_sum(row):
    return row.sum()
 
# 对每一行应用row_sum函数
row_sums = df.apply(row_sum, axis=1)
 
print(row_sums)

在这个例子中,row_sum 函数被应用于DataFrame的每一行,计算每行的和,并返回一个Series。

使用lambda函数

1045. 买下所有产品的客户

# 使用lambda函数对每一列的元素乘以2
df_multiplied = df.apply(lambda x: x * 2)
 
print(df_multiplied)

在这个例子中,一个lambda函数被用于将DataFrame中每个元素乘以2。

处理复杂的数据结构

如果你的DataFrame包含复杂的数据结构(如列表或字典),你可以编写更复杂的函数来处理这些数据。

# 创建一个包含列表的DataFrame
df_complex = pd.DataFrame({
    'data': [[1, 2], [3, 4], [5, 6]]
})
 
# 定义一个函数,计算列表中元素的和
def sum_list(lst):
    return sum(lst)
 
# 对'data'列应用sum_list函数
sums = df_complex['data'].apply(sum_list)
 
print(sums)

在这个例子中,sum_list 函数被用于计算DataFrame中’data’列每个列表元素的和。

注意事项

  • 当对大型DataFrame使用 apply() 时,性能可能会受到影响,因为Pandas需要将数据逐行或逐列传递给Python函数。在可能的情况下,优先考虑使用Pandas的内置向量化操作来提高性能。
  • 如果你的函数返回多个值,并且你希望对行应用该函数,确保你的函数返回一个Series或类似的结构,这样Pandas才能正确地将其组装成一个新的DataFrame。

map()

在 pandas 中,map 函数是一种用于将一个函数或映射关系应用到 DataFrame 或 Series 的每个元素上的方法。对于 Series 对象,map 方法特别有用,因为它允许你将一个函数、字典或 Series 应用到 Series 的每个元素上,并返回一个新的 Series,其中包含应用映射后的结果。

以下是 map 方法的一些常见用法:

在 Series 中

import pandas as pd
 
# 创建一个 Series
s = pd.Series([1, 2, 3, 4, 5])
 
# 定义一个函数
def square(x):
    return x ** 2
 
# 使用 map 方法应用函数
squared_s = s.map(square)
print(squared_s)

在这个例子中,square 函数被应用到 s Series 的每个元素上,结果是一个包含每个元素平方的新 Series。

字典进行映射

627. 变更性别

# 创建一个 Series
s = pd.Series(['cat', 'dog', 'fish', 'cat'])
 
# 定义一个映射字典
animal_to_sound = {'cat': 'meow', 'dog': 'woof', 'fish': 'glub'}
 
# 使用 map 方法应用字典映射
sounded_s = s.map(animal_to_sound)
print(sounded_s)

在这个例子中,animal_to_sound 字典被用来将动物名称映射到它们的声音,结果是一个包含映射后声音的新 Series。

另一个 Series 进行映射

# 创建两个 Series
s1 = pd.Series(['a', 'b', 'c', 'd'])
s2 = pd.Series(['apple', 'banana', 'cherry', 'date'], index=['a', 'b', 'c', 'd'])
 
# 使用 map 方法应用 Series 映射
mapped_s = s1.map(s2)
print(mapped_s)

在这个例子中,s2 Series 被用作映射,将 s1 中的每个元素映射到 s2 中对应索引的值。注意,如果 s1 中的某个元素在 s2 的索引中找不到,结果将是 NaN

对于 DataFrame,map 方法通常不是直接应用的,因为 DataFrame 是二维的,包含行和列。相反,你可能会对 DataFrame 的某一列使用 map 方法,或者对整个 DataFrame 使用 applymap 方法(但请注意,applymap 是应用于每个元素的,与 map 在 Series 上的行为类似,但它不接受函数以外的映射器)。

这里有一个对 DataFrame 列使用 map 的例子:

# 创建一个 DataFrame
df = pd.DataFrame({
    'Animal': ['cat', 'dog', 'fish', 'cat'],
    'Age': [2, 3, 1, 4]
})
 
# 使用 map 方法对 'Animal' 列应用字典映射
df['Sound'] = df['Animal'].map(animal_to_sound)
print(df)

在这个例子中,animal_to_sound 字典被用来将 df DataFrame 中 'Animal' 列的每个元素映射到它们的声音,结果是一个新的列 'Sound'

索引操作

idxmax()

总结:

DataFrame.idxmax():返回每列的最大值的行索引

Series.idxmax():返回单列的最大值的行索引

在 Pandas 中,idxmax() 函数用于返回指定轴上最大值的索引。这个函数对于寻找数据集中某个特定列(或行,取决于你如何应用它)的最大值的位置非常有用。

基本用法

假设你有一个 Pandas DataFrame 或 Series,idxmax() 会返回包含最大值的行(对于 DataFrame,默认是列方向)或元素(对于 Series)的索引。

import pandas as pd
 
# 创建一个简单的 DataFrame
df = pd.DataFrame({
    'A': [1, 20, 3, 4],
    'B': [5, 6, 70, 8]
})
 
# 对列 'A' 使用 idxmax()
max_index_A = df['A'].idxmax()
print(f"Column 'A' maximum value index: {max_index_A}")
 
# 对整个 DataFrame 使用 idxmax(),默认是 axis=0(列方向)
max_index_df = df.idxmax()
print(f"DataFrame maximum value indices (column-wise): {max_index_df}")
 
# 对 DataFrame 使用 idxmax(),指定 axis=1(行方向)
max_index_df_row = df.idxmax(axis=1)
print(f"DataFrame maximum value indices (row-wise): {max_index_df_row}")

输出

Column 'A' maximum value index: 1
DataFrame maximum value indices (column-wise): A    1
B    2
dtype: int64
DataFrame maximum value indices (row-wise): 0    B
1    A
2    B
3    B
dtype: object

解释

  • 对于 df['A'].idxmax(),它返回列 ‘A’ 中最大值(20)的索引(1)。

  • 对于 df.idxmax()(默认 axis=0),它返回每一列中最大值的索引。在这个例子中,列 ‘A’ 的最大值在索引 1,列 ‘B’ 的最大值在索引 2。

  • 对于 df.idxmax(axis=1),它返回每一行中最大值的列索引。在这个例子中,第一行的最大值在列 ‘B’,第二行的最大值在列 ‘A’,依此类推。

注意事项

  • 如果存在多个最大值并且你想要找到它们所有的索引,idxmax() 只会返回第一个找到的最大值的索引。
  • 如果 DataFrame 或 Series 是空的,idxmax() 会抛出一个 ValueError
  • 如果 DataFrame 中包含 NaN 值,并且你想要在忽略 NaN 的情况下找到最大值,你应该先使用 dropna() 方法去除 NaN 值,然后再应用 idxmax()

reset_index()

在Pandas中,reset_index() 方法用于重置 DataFrame 或 Series 的索引。这个操作通常在你对数据进行了排序、分组、过滤等操作后,索引变得不再连续或不再是整数时特别有用。通过重置索引,可以使索引重新变为从 0 开始的整数序列,或者可以将某个列的值设置为新的索引。

以下是 reset_index() 方法的一些常用参数及其作用:

  • drop(布尔值,默认为 False):如果为 True,则不将旧索引添加为列;如果为 False,则旧索引会被添加为新的 DataFrame 的一列。
  • inplace(布尔值,默认为 False):如果为 True,则直接在原 DataFrame 上修改,不返回新的 DataFrame。
  • level(整数或索引级别名称,或级别列表):仅对多级索引有效。指定要重置的索引级别。
  • col_level(整数或索引级别名称):如果 DataFrame 的列是多级索引,则此参数指定用于新索引的列级别。
  • col_fill(字符串):用于填充多级列索引中缺失级别的值。

示例

参数name

596. 超过 5 名学生的课

例如,假设有一个DataFrame,其中’Name’列被设置为索引。如果想要重置这个索引,并且希望新的索引列有一个特定的名称(比如’ID’),就可以这样做:

df.set_index('Name', inplace=True)  # 将'Name'列设置为索引
reset_df = df.reset_index(name='ID')  # 重置索引,并指定新索引列的名称为'ID'

执行上述代码后,原来的’Name’索引就会被重置,并且会添加一个新的名为’ID’的列,其中包含了原来的索引值。

无参数

假设我们有一个 DataFrame:

import pandas as pd
 
df = pd.DataFrame({
    'A': ['foo', 'bar', 'baz', 'qux'],
    'B': [1, 2, 3, 4]
})
df = df.set_index('A')
print(df)

输出:

B
A     
foo  1
bar  2
baz  3
qux  4

现在我们将索引重置:

df_reset = df.reset_index()
print(df_reset)

输出:

A  B
0  foo  1
1  bar  2
2  baz  3
3  qux  4

可以看到,原来的索引 ‘A’ 现在成为了一列,并且添加了一个新的从 0 开始的整数索引。

参数drop

如果我们不想保留原来的索引作为列,可以设置 drop=True

df_reset = df.reset_index(drop=True)
print(df_reset)

输出:

B
0  1
1  2
2  3
3  4

此时,原来的索引 ‘A’ 被丢弃,只保留了数据列 ‘B’ 和一个新的整数索引。

多级索引

对于多级索引,可以使用 level 参数来指定要重置的级别:

# 创建一个多级索引的 DataFrame
multi_index = pd.MultiIndex.from_tuples([('foo', 'one'), ('foo', 'two'), ('bar', 'one'), ('bar', 'two')], names=['A', 'B'])
df_multi = pd.DataFrame({'C': [1, 2, 3, 4]}, index=multi_index)
print(df_multi)
 
# 重置 'A' 级别的索引
df_reset_multi = df_multi.reset_index(level='A')
print(df_reset_multi)

T

转置:列, 行交换

元素定位

at

626. 换座位

  • 用于访问单个值(标量访问),基于标签(label)进行索引。
  • 只能用于访问单个元素,如果访问多个元素会引发错误。
  • 适用于快速访问已知标签的数据。

df.at[row_label, column_label]

iat

  • 类似于at,但基于整数位置进行标量访问。
  • 适用于快速访问已知位置的单个元素。
df.iat[row_position, column_position]

loc

  • 基于标签(label)进行索引,可以用于访问单个值或一组值。
  • 支持切片操作,可以访问行或列的子集。
  • 适用于基于标签的复杂查询。

df.loc[row_labels, column_labels]

iloc

  • 基于整数位置(integer position)进行索引,用于访问单个值或一组值。
  • 支持切片操作,可以访问行或列的子集。
  • 适用于基于位置的索引,当标签不是整数或不方便使用标签时很有用。

df.iloc[row_positions, column_positions]

两个序列操作

isin()

570. 至少有5名直接下属的经理

在 Pandas 中,isin() 方法用于过滤数据框(DataFrame)或序列(Series)中的元素,检查它们是否包含在指定的值列表或序列中。该方法返回一个布尔型对象(对于 DataFrame,返回一个布尔型的 DataFrame;对于 Series,返回一个布尔型的 Series),其中 True 表示元素包含在指定的值中,False 表示不包含。

以下是 isin() 方法的基本用法:

对于 Series

import pandas as pd
 
# 创建一个 Series
s = pd.Series([1, 2, 3, 4, 5])
 
# 使用 isin() 方法检查 Series 中的元素是否包含在 [1, 3, 5] 中
filtered_s = s[s.isin([1, 3, 5])]
 
print(filtered_s)

输出将会是:

0    1
2    3
4    5
dtype: int64

对于 DataFrame

import pandas as pd
 
# 创建一个 DataFrame
df = pd.DataFrame({
    'A': [1, 2, 3, 4, 5],
    'B': [10, 20, 30, 40, 50]
})
 
# 使用 isin() 方法检查 DataFrame 的列 'A' 中的元素是否包含在 [1, 3, 5] 中
filtered_df = df[df['A'].isin([1, 3, 5])]
 
print(filtered_df)

输出将会是:

A   B
0  1  10
2  3  30
4  5  50

你也可以对 DataFrame 的多列使用 isin() 方法,但这时你需要分别对每个列进行过滤,或者结合使用其他逻辑操作(如 &|)来组合多个过滤条件。

对多列使用 isin()(结合逻辑操作)

# 假设我们想要过滤出列 'A' 中的元素在 [1, 3] 中且列 'B' 中的元素在 [10, 30, 50] 中的行
combined_filter = (df['A'].isin([1, 3]) & df['B'].isin([10, 30, 50]))
filtered_df_multi = df[combined_filter]
 
print(filtered_df_multi)

输出将会是:

A   B
0  1  10
2  3  30
4  5  50  # 注意:虽然 5 在 [1, 3] 中不在,但 50 在 [10, 30, 50] 中,所以这一行不会单独因为 B 列而被选中
# 但由于 5 不在 [1, 3] 中,所以实际上这一行不会被包括在结果中,这里只是为了解释逻辑操作。
# 正确的输出不会包含索引为 4 的行,因为它不满足 A 列的条件。

注意:上面的多列过滤示例中,我犯了一个错误并给出了一个误导性的输出解释。正确的行为是,只有当行同时满足所有列的条件时,它才会被包括在结果中。因此,在上面的例子中,索引为 4 的行不会被包括,因为 A 列的值 5 不在 [1, 3] 中。正确的输出应该只包含索引为 0 和 2 的行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值