解锁pandas数据处理奥秘

文章标题:

探索pandas数据处理的核心要义

文章内容:pandas相关

pandas的主要操作涵盖:索引选取、数据过滤、数据的增删改查、分组聚合、数据清洗、合并操作以及数据可视化呈现

1. dataframe筛选

当需要从dataframe的特定列中筛选出包含特定值的行,且特定列的数量不固定、各列的特定值也各不相同时,该如何进行操作?

import pandas as pd

# 创建示例数据
data = {'A': [1, 2, 3, 4],
        'B': [5, 6, 7, 8],
        'C': [2, 2, 7, 8],
        'D': [2, 6, 7, 2]}

df = pd.DataFrame(data)

# 为不同列定义特定值
specific_values = {'A': 2, 'B': 6, 'C': 2, 'D': 6}

# 初始化筛选条件
filter_condition = pd.Series(True, index=df.index)

# 根据每列的要求分别处理
for col, value in specific_values.items():
    filter_condition = filter_condition & (df[col] == value)

# 应用筛选条件
filtered_df = df[filter_condition]

print(filtered_df)


## 方法2,使用query
# 构造查询条件
query_string = ' & '.join([f'{col} == {val}' for col, val in specific_values.items()])
# 使用query进行筛选
filter_df = df.query(query_string)

总结:

query() 函数适用于快速进行数据筛选,在处理简单的列值筛选时,具有较好的性能表现。

np.all() 是一种高效的方法,适用于需要筛选多个列的场景,通常比apply()等方法更为快捷。

apply() 函数适用于更为复杂的条件筛选,但性能相对较低,适合在对性能要求不高的情况下使用。

isin() 函数在处理多个可选值时十分有效,但不适用于范围比较的情况。

关于dataframe筛选出排除特定几行的数据

2. 在字典中根据值查找键

def find_keys_by_value(d, value):
    keys = [key for key, val in d.items() if val == value]
    return keys

3. 依据dataframe的groupby层级关系构建树。【可考虑借助图数据库,后续进一步探究】

若dataframe包含两列值value1和value2,其余列保持不变

import pandas as pd

# 示例 DataFrame
data = {
    'Level1': ['A', 'A', 'A', 'B', 'B', 'C'],
    'Level2': ['X', 'Y', 'Y', 'Z', 'Z', 'X'],
    'Level3': ['M', 'N', 'O', 'P', 'Q', 'R'],
    'Value1': [1, 2, 3, 4, 5, 6],
    'Value2': [10, 20, 30, 40, 50, 60]
}
df = pd.DataFrame(data)

# 定义构建树的递归函数
def build_tree(df, group_cols, value_cols):
    if len(group_cols) == 0:
        return df[value_cols].to_dict('records')

    current_col = group_cols[0]
    grouped = df.groupby(current_col)
    tree = {}

    for name, group in grouped:
        tree[name] = build_tree(group, group_cols[1:], value_cols)

    return tree

# 构建树
group_cols = ['Level1', 'Level2', 'Level3']
value_cols = ['Value1', 'Value2']
tree = build_tree(df, group_cols, value_cols)

4. 在dataframe中,对特定的两列按照某函数的计算规则,对所有行进行计算并生成新列

import pandas as pd

# 创建示例 DataFrame
data = {'A': [10, 20, 30, 40],
        'B': [2, 4, 6, 8]}

df = pd.DataFrame(data)

# 定义应用于两列的自定义函数
def custom_function(x, y):
    return x + y * 2  # 示例函数:将列A的值与列B值的两倍相加

# 应用自定义函数到两列并创建新列'C'
df['C'] = df.apply(lambda row: custom_function(row['A'], row['B']), axis=1)

# 显示更新后的 DataFrame
print(df)
方法 适用对象 作用范围 示例
apply DataFrame / Series 对列、行或元素应用函数 对每列或每行应用函数
axis=0 或默认值:对每列操作。
axis=1:对每行操作
applymap DataFrame 对 DataFrame 每个元素应用函数 对 DataFrame 中每个元素应用函数
map Series 对 Series 的每个元素应用函数 替换或映射 Series 中的每个元素
transform DataFrame / Series 对 Series 或 DataFrame 应用元素级转换 对 Series 或 DataFrame 中的每个元素进行转换,通常保持原数据形状

5. 使用pd.ExcelWriter

将多个dataframe写入Excel文件的不同sheet

6. 数据切片操作

data.iloc[1:10,2:4]#前面是行,后面是列
有如下形式的切片
cols = list(range(7, 103)) + list(range(107, data.shape[1]))
data.iloc[4:-1, cols]

7. df数据去重

import pandas as pd
dict={'x':[1,2,3,6],'y':[1,4,1,1],'z':[1,2,4,1]}
df=pd.DataFrame(dict)

## subset可以指定重复的列,进行去重
df.drop_duplicates(subset=['y','z'],keep='first',inplace=True)

8. 依据时间进行排序

weekofyear_sum中'year'列确实存在重复的值以便触发第二列 'weekofyear'的排序

data_group[i][1].sort_values(by='data_date')
# 同时对两列值排序 True是升序
weekofyear_sum.sort_values(by=['year', 'weekofyear'], ascending=[True, True], inplace=True)

9. shift函数的应用

实现对每一天中的相邻行批次号不同的个数进行聚合,并且最后得到整段时间内的平均每天相邻行批次号不同的个数

import pandas as pd

# 示例数据
data = {
    'datetime_column': pd.to_datetime(['2025-03-20', '2025-03-20', '2025-03-21', '2025-03-21', '2025-03-22']),
    '工序名称': ['A', 'A', 'B', 'B', 'A'],
    '工序代码': [101, 101, 102, 102, 101],
    '工单ID': [1001, 1002, 1003, 1004, 1005],
    '批次号': ['B123', 'B123', 'B456', 'B456', 'B123'],
    '物资编码': ['M001', 'M002', 'M003', 'M004', 'M005'],
    '过数智能单元': ['X', 'X', 'Y', 'Y', 'X']
}

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

# 定义 sub_select 函数进行按日期分组聚合
def sub_select(df):
    # 按日期分组
    df['日期'] = df['datetime_column'].dt.date  # 提取日期部分(去掉时间)

    # 计算每一天中相邻行批次号不同的个数
    df['批次号不同'] = (df['批次号'] != df['批次号'].shift()).astype(int)

    # 按日期分组并计算每一天批次号不同的个数
    daily_diff_counts = df.groupby('日期')['批次号不同'].sum()

    # 计算所有天的平均批次号不同的个数
    average_daily_diff = daily_diff_counts.mean()

    return average_daily_diff

# 计算分组后的结果
result = df.groupby(['工序名称', '工序代码', '过数智能单元']).apply(sub_select)

# 打印结果
print(result)

10. 筛选

10.1. 对某一列中的特定值进行筛选

# 筛选出某列是特定值的行
data[data["target"] == "taget1"]
# 筛选出某列是特定值的行,此特定值包含多种情况
lines = ["a", "b", "c"]
data = data[data['sku_id'].isin(lines)]

10.2. 对多列中的特定值进行筛选

import pandas as pd

# 新建dataframe
df1 = pd.DataFrame({
    "A": [25, 30, 35, 40],
    "B": ['A', 'B', 'C', 'D'],
    "C": ['X', 'Y', 'Z', 'W'],
    "D": [1, 2, 3, 4]
})

filter_series = pd.Series({
    "C": 30,
    "B": "A"
})

# 映射字典
column_mapping = {
    "C": "A",
}

filter_df = df1[df1.apply(lambda row: all(row[column_mapping.get(col, col)] == val for col, val in filter_series.items()), axis=1)]

11. 数据排序

12. 数据分组

# 按某一列分组
after_gb = df.groupby("col_name")
# 分组之后可以将group类型转为list类型进行查看
after_gb_list = list(after_gb)
# list之后的数据结构是元组形式,元组中包含col_name也包含dataframe
for name, data in after_gb:
    print(name)
    print(data) # 遍历出来的data是dataframe的数据格式
after_gb.sum() # 分组之后的聚合操作
after_gb.mean() # 分组
after_gb["col_name"].transform("sum") # 将求和结果分到每一行上,返回series
# 过滤:删除某些行
例如:
after_gb.filter(lambda x: x["销量"].sum() > 6)

13. 拼接

拼接用法

官方文档指南

dataframe的拼接有四个函数可以使用,分别是merge、join、concat、compare,其中文含义分别为合并、连接、串联、对比。

13.1. 串联操作(concat函数)

concat函数中axis的用法

concat函数参数介绍及用法代码示例

concat默认是按轴拼接,轴指的是行index。即默认参数axis = 0。

# concat函数(上下拼接)
df = pd.concat(objs, axis=0, ignore_index=False, join="outer")
# objs: 指的是要合并的dataframe(们)。可以是一个列表[df1,df2,...]也可以是一个集合(df1,df2,...)
# axis:dataframe拼接的方向。默认axis=0,上下拼接;设置axis=1,左右拼接
# ignore_index:是否需要重新设置索引,默认是False
# join:默认join = "outer",非交集用nan填。若join = "inner",显示交集

当两个单列dataframe想要进行上下拼接并形成单列时,需注意列名必须一致。

s1 = pd.Series(['a', 'b', 'c'], index=[0, 1, 2])
s2 = pd.Series(['d', 'e', 'f'], index=[0, 1, 2])
s1df = s1.to_frame(name='值')
s2df = s2.to_frame(name='值3')

s12 = pd.concat([s1df, s2df])
print(s12)
#      值   值3
# 0    a  NaN
# 1    b  NaN
# 2    c  NaN
# 0  NaN    d
# 1  NaN    e
# 2  NaN    f

# 创建两个示例 DataFrame,包含相同的列名
df1 = pd.DataFrame({
    'A': [1, 2, 3],
    'B': [4, 5, 6]
})
df2 = pd.DataFrame({
    'A': [7, 8, 9],
    'B': [10, 11, 12]
})
# 使用 pd.concat 进行横向拼接
result = pd.concat([df1, df2], axis=1)
# 打印结果
print(result)
#   A  B  A   B
# 0  1  4  7  10
# 1  2  5  8  11
# 2  3  6  9  12

13.2. merge

pandas.DataFrame.merge()参数详解

是使用数据库风格的连接合并DataFrame或已命名的系列对象

DataFrame.merge(left, right, how='inner', on=None, left_on=None, right_on=None,
                left_index=False, right_index=False, sort=False, suffixes=('_x', '_y'),
                copy=True, indicator=False, validate=None)
# 关键参数为left_df,right_df、how、on
# how有 {‘left’, ‘right’, ‘outer’, ‘inner’}, default ‘inner’ 默认为合并两个frame的交集
# on表示连接时,参考的主键。可以是一个,也可以是多个。

如果基于两边的索引合并,使用 left_index=True 和 right_index=True

13.3. 左连接时,发现左边表格行数变多的原因

右边表格存在重复的行:
在左连接中,左表的每一行会与右表中满足连接条件的行进行匹配。若右表中某个值出现多次,那么左表中相应的每一行都会与右表中的每一匹配行进行组合,从而导致左表的行数增加。

例如

 * 左表(A):  ID | Name

---|---
1 | Tom
2 | Jerry
* 右表(B): ID | Score
---|---
1 | 90
1 | 85
2 | 88

当对这两个表进行左连接时,左表的行数会增加,因为 ID 为 1 的行在右表中有两条记录,结果如下:

ID Name Score
1 Tom 90
1 Tom 85
2 Jerry 88

这里,ID 为 1 的行出现了两次。

解决办法

  • 可通过检查右表是否有重复行来避免该问题,或使用 DISTINCT 语句去除重复项。
  • 若不希望某些行重复,可通过调整连接条件或使用合适的聚合函数来控制重复数据。

14. dataframe与ndarray的相互转换

df.values
pd.DataFrame(ndarray)

15. 向dataframe中添加多列

df[['column_new_1', 'column_new_2', 'column_new_3']] = pd.DataFrame([[np.nan, 'dogs', 3]], index=df.index)

16. 修改dataframe的列名

pandas DataFrame数据重命名列名的几种方式

16.1. 删除特定行

obj_cols = ["data_date", "destination_country", "service_level_name", "goods_type_name"]
df_dropped = i_df_T.drop(index=obj_cols) # 删除行名为obj_cols的行

17. 将dataframe输出为excel文件

```python
import pandas as pd

创建一个示例 DataFrame

data = {'A': [1, 2, 3], 'B': [4, 5

版权声明:程序员胖胖胖虎阿 发表于 2025年7月20日 上午7:51。
转载请注明:解锁pandas数据处理奥秘 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...