1. pandas
pandas最常用的操作:索引、过滤、数据增删查改、分组聚合数据清理、合并、数据可视化
1.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 筛选出排除特定几行的数据
1.2. 在dict中根据value找key
def find_keys_by_value(d, value):
keys = [key for key, val in d.items() if val == value]
return keys
1.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)
1.4. dataframe中,特定的两列按照某个函数的计算规则,将所有行计算一遍,生成新的数,存在dataframe的新列中。
import pandas as pd
# Create an example DataFrame
data = {'A': [10, 20, 30, 40],
'B': [2, 4, 6, 8]}
df = pd.DataFrame(data)
# Define a custom function to apply to the two columns
def custom_function(x, y):
return x + y * 2 # Example function: add column A with twice the value of column B
# Apply the custom function to the two columns and create a new column 'C'
df['C'] = df.apply(lambda row: custom_function(row['A'], row['B']), axis=1)
# Display the updated 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 中的每个元素进行转换,通常保持原数据形状 |
1.5. pd.ExcelWriter
将多个dataframe写入EXcel文件的不同sheet
1.6. 数据切片
data.iloc[1:10,2:4]#前面是行,后面是列
有如下形式的切片
cols = list(range(7, 103)) + list(range(107, data.shape[1]))
data.iloc[4:-1, cols]
1.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)
1.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)
1.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)
1.10. 筛选
1.10.1. 某一列中特定值进行筛选
# 筛选出某列是特定值的行
data[data["target"] == "taget1"]
# 筛选出某列是特定值的行,此特定值包含多种情况
lines = ["a", "b", "c"]
data = data[data['sku_id'].isin(lines)]
1.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.item()), axis = 1)]
1.11. 排序
1.12. 分组
# 按某一列分组
after_gb = df.groupby("col_name")
分组之后可以将group类型转为list类型进行查看
after_gb_list = list(after_gb)
list之后的数据结构是元组形式,元组中包含col_name也包含dataframe
for name, data in after_df:
print(name)
print(data) # 遍历出来的data是dataframe的数据格式
after_df.sum() # 分组之后的聚合操作
after_df.mean() # 分组
after_df["col_name"].transform("sum") # 将求和结果分到每一行上,返回series
过滤:删除某些行
例如:
after_df.filter(lambda x: x["销量"].sum() > 6)
1.13. 拼接
dataframe的拼接有四个函数可以使用,分别是merge、join、concat、compare,其中文含义分别是合并、连接、串联、对比。
1.13.1. concatenate-串联(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
1.13.2. 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
1.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 的行出现了两次。
- 左表(A):
解决办法:
- 可以通过检查右表是否有重复行来避免这一问题,或者使用
DISTINCT
语句来去除重复项。 - 如果不希望某些行重复,可以通过调整连接条件或使用合适的聚合函数来控制重复数据。
1.14. dataframe转ndarray、ndarray转dataframe
df.values
pd.dataframe(ndarray)
1.15. 增加多列
df[['column_new_1', 'column_new_2', 'column_new_3']] = pd.DataFrame([[np.nan, 'dogs', 3]], index=df.index)
1.16. 修改列名
1.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的行
1.17. 输出为excel
import pandas as pd
# 创建一个示例 DataFrame
data = {'A': [1, 2, 3], 'B': [4, 5, 6]}
df = pd.DataFrame(data)
# 输出为 Excel 文件,不包含索引
df.to_excel('df.xlsx', index=False)