使用pandas遇到的一些坑及解决方案(3)

本次内容以及坑主要涉及四个方面:apply函数使用,groupby分组取每组前几个值,df遍历,筛选集合,分享一下,如果有可以优化的地方,不吝赐教,谢谢。

文章目录

  • apply函数
    • 需求描述
    • 示例代码
  • 取反筛选集合
    • 需求描述
    • 示例代码
  • 取分组后每组的前几个数据
    • 需求描述
    • 示例代码
  • 遍历操作
    • iterrows
      • 解释及坑
      • 示例代码
    • values()
      • 示例代码

apply函数

需求描述

个人觉得dataframe数据处理用apply函数都很好用,不论是lambda函数还是自定义函数,但是需要注意

  1. 如果用lambda函数,那么条件要用()括起来,而且lambda函数所用的逻辑符号为:&(and),|(or)
  2. 如果用lambda函数,对每一行进行操作的话,需要加上axis=1的参数
  3. 一般来讲简单的逻辑筛选用lambda即可,复杂的逻辑要使用自定义函数

示例代码

import numpy as np
import pandas as pd

df = pd.DataFrame({"省": ["辽宁", "辽宁", "辽宁", "四川", "四川", "四川", "四川", "山东", "山东"], "市": ["沈阳", "大连", "盘锦", "成都", "资阳", "绵阳","乐山", "青岛", "菏泽"]})

# 根据数据集大小将某列生成随机模拟数
df["篮球场个数"] = np.random.randint(1000000, 5000000, size=len(df))
# 还有一种方法, 这里提一下,某个范围内的数
# df.loc[:, "篮球场个数"] = np.arange(len(df))

# 最简单的情况(可能因为某些原因需要添加辅助列)
df["状况"] = df.apply(lambda x: "合适" if (x.篮球场个数 > 500000) & (x.篮球场个数 < 3000000) else "不合适", axis=1)
print(df)

# 稍微复杂点的,需要实现自己的逻辑(这里假设要对篮球场进行考察附加条件)
def calc_para(df):
    if (df.省 == "辽宁" and df.市 == "大连") or (df.省 == "四川" and df.市 == "成都"):
        return "严重考察"
    elif df.省 == "辽宁" and df.市 == "葫芦岛":
        return "派人取查"
    else:
        return "随机抽查"

# 不需要传入参数,默认参数就为df, axis=1代表着将每一行拿到自定义函数中进行运算
df["参考条件"] = df.apply(calc_para, axis=1)
print(df)

取反筛选集合

需求描述

有时候在筛选数据集的时候往往条件很复杂,但是这些复杂的对立条件却只有一个,这种情况下就可以通过对立条件取反筛选所需要的数据一般来讲,主要还是针对isin或者df[df.column_name==""]这种条件

示例代码

# 还是用上面的数据
# 需求为不要沈阳的数据(我这里因为数据集合比较简单,需求也只有一个条件,如果是多个条件同时需要满足,那么可能直接筛选就不是很清晰)
df = df[df.!= "沈阳"]
print(df)

# 如果提交见很多,那么可能上面的方法就满足不了条件
# 不看沈阳的数据(~取反的话必须后面要将所有取反条件括起来)
df = df[~(df.== "沈阳")]
print(df)

取分组后每组的前几个数据

需求描述

还是以第一个代码为例,假如需要筛选出每个省份拥有篮球场最多的2个地级市,因为我最开始是用for循环迭代做的,后面知道这个方法,确实优秀,分享一下

示例代码

# 将每个省市篮球场由大到小排序
df.sort_values(by=["省", "市", "篮球场个数"], ascending=False, inplace=True)
# 提取出每个省篮球场个数排名前两名的市
tmp_df = df.groupby(by=["省"]).head(2)
print(tmp_df)

遍历操作

iterrows

解释及坑

  • datdaframe.iterrows()是返回迭代器,一般是用for语句调用, 返回为当前df所在行索引以及那一行具体数据
  • 用for循环调用,不可以直接把当前行的数据进行计算,应该把要计算的数据先用变量接收,再进行整合计算
  • 索引在你需要更改df的某一列的值时特别好用

示例代码

# 这里要根据条件对add_symbol列进行更改,满足条件的由 0 变更为 1
tmp_repo_df = pd.DataFrame({"actqty_add": [100, 200, 300, 400], "conversion": [10, 5, 5, 50]})
tmp_repo_df["add_symbol"] = 0


diff = 100
sum_amount = 0
for index, item in tmp_repo_df.iterrows():
    # 不能够直接进行比如 sum_amount += item["actqty_add"] / item["conversion"]这种操作
    actqty_add = item["actqty_add"]
    conversion = item["conversion"]
    sum_amount += actqty_add / conversion
    if sum_amount > diff:
        # 保证最后一次的增加超过diff
        tmp_repo_df.loc[index, "add_symbol"] = 1
        break
    tmp_repo_df.loc[index, "add_symbol"] = 1

values()

用for循环每一行会生成一个列表,方便的是可以用列表的命令操作,一般用于对数据的处理和集成,相比较iterrows来说,可能唯一的好处是可以根据列表方法对数据进行操作

示例代码

# 将同一个stpid的汇总,并生成分类汇总的字典,为后面映射做个缓存
df = pd.DataFrame({"stpid": ["A", "B", "C","B", "C", "A"], "org":["1014", "1015", "1016", "1018", "5000", "9000"]})
org_group = df.groupby(["stpid"])["org"].apply(lambda x: x.str.cat(sep=",")).reset_index()
stpid_organ_dic = {}
for i in org_group.values:
    organs = i[1].split(",")
    stpid_organ_dic.update({i[0]: organs})
print(stpid_organ_dic)

你可能感兴趣的:(使用pandas遇到的一些坑及解决方案(3))