Python(或一般CS)中的循环或分层字典式数据结构?

Python(或一般CS)中的循环或分层字典式数据结构?,python,pandas,dataframe,dictionary,data-structures,Python,Pandas,Dataframe,Dictionary,Data Structures,由于我有一个大熊猫数据帧(超过100万行),并且我正在查看3列,因此我目前处于茫然状态,即: Company_Name Business_ID Location ABC, Inc. BY2389AS MTV ABC, Inc. 100020 LMD XYZW 010012 MTV XYZW 010012 LMD XYZW

由于我有一个大熊猫数据帧(超过100万行),并且我正在查看3列,因此我目前处于茫然状态,即:

Company_Name     Business_ID    Location
ABC, Inc.         BY2389AS        MTV
ABC, Inc.          100020         LMD
XYZW               010012         MTV
XYZW               010012         LMD
XYZW              AB23JKF         QAT
                  BA23F3              
SomethingCo        2342
SomethingCo                       ALD
可以看出,有时一些字段丢失。我想根据给定的注册表检查这一点(它包含数百万个CSV格式的三元组(公司名称、业务ID、位置),如果存在唯一匹配,请尝试返回缺少的字段(如果存在唯一匹配)

注册表的CSV格式如下所示:

Company_Name, Business_ID, Location
ABC, Inc., BY2389AS, MTV
ABC, Inc., 100020, LMD
XYZW, 010012, MTV
XYZW, 010012, LMD
XYZW, AB23JKF, QAT
DLCComp, BA23F3, PLT
DLCComp, 234XYZ, QAT            
SomethingCo, 2342, COD
SomethingCo, 2020 , ALD
如上所示,此CSV文件中没有任何内容缺失

需要注意的是,执行数据帧groupby、pivot表、堆栈/取消堆栈甚至逻辑查找并选择数据帧的子集会降低查找速度(因为查看整个注册表需要很长的时间。我有一套逻辑需要检查,如果某些字段缺失,请查看注册表以处理唯一匹配并填写缺失的字段;否则,如果无法识别唯一匹配,请按原样返回。)

字典查找似乎很理想,但由于3个字段的任意组合都可能丢失,所以我无法从这个巨大的注册表数据框(出于当前目的,我将其读入内存)创建字典,并通过其中一列创建键

我试图思考什么样的数据框架最适合处理这个问题,并考虑循环或分层字典(如果存在的话),但这也变得有点复杂,因为根据数据库和注册表中缺少的值,查找必须调整到不同的键值对。根据可用的列值重新排列或子集数据帧的成本需要一段时间,我正在尝试找出r算法可以解决这个问题。我还试图看看Pandas是否有一种非常有效的方法,通过逻辑操作(这就是我目前正在做的)对数据帧进行子集设置,如下所示:

这只是一个函数,用于处理填充了Business_ID但未填充Company_Name和Location的特殊情况。可以看出,这可能会变得复杂。我目前正在处理所有8个案例(其中一些案例可以减少为重复案例或基本相同的案例,因此总共大约有4个案例和几个子类),但这在设计和性能上似乎都非常低效。当使用行数为800000的注册表CSV数据子集并在大约400个数据点上执行这种类型的逻辑时,使用%timeit使用128毫秒的stdev需要35秒。我使用了df.apply,使用了我设计用于计时的主函数

我想知道一种数据结构,当将其应用于更大的数据帧时,它可以提供良好的查找和设置时间-我知道必须有一种更有效的方法,无论是高效地使用Pandas方法还是不同的数据结构,例如互查字典(或者循环或层次字典,如果这些概念存在的话)、潜在的基于树的方法或其他东西。我欢迎对此的任何意见

解决方案1-优化数据帧搜索

输出:

Dummy registry_df size = 217.666774 MB

        A               B             C
0   abcdefghi_0   jklmnopqrs_0    tuvwxyz_0
1   abcdefghi_1   jklmnopqrs_1    tuvwxyz_1
2   abcdefghi_2   jklmnopqrs_2    tuvwxyz_2
3   abcdefghi_3   jklmnopqrs_3    tuvwxyz_3
4   abcdefghi_4   jklmnopqrs_4    tuvwxyz_4
2.99 s ± 278 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>

输出:

11.9 s ± 338 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
11.4 s ± 441 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
13 s ± 756 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
5.57 s ± 384 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
5.22 s ± 122 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
3.99 s ± 140 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
解决方案2-如果您有一点额外的内存,请将索引存储在相应的列字典中

输出:

948 ms ± 64.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
27.7 ms ± 2.47 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
> 创建包含索引的字典

dict_Company_Name ={}
dict_Business_ID = {}
dict_Location = {}

def Create_Dictionary_From_DataFrame(df, dict_Company_Name, dict_Business_ID, dict_Location):
    for row_Index in range(len(df)):
        comany_name, business_id, location = df.iloc[row_Index]
        dict_Company_Name.setdefault(comany_name, []).append(row_Index)
        dict_Business_ID.setdefault(business_id, []).append(row_Index)
        dict_Location.setdefault(location, []).append(row_Index)

%time Create_Dictionary_From_DataFrame(df, dict_Company_Name, dict_Business_ID, dict_Location)

Wall time: 2min 12s

输出:

Dummy registry_df size = 217.666774 MB

        A               B             C
0   abcdefghi_0   jklmnopqrs_0    tuvwxyz_0
1   abcdefghi_1   jklmnopqrs_1    tuvwxyz_1
2   abcdefghi_2   jklmnopqrs_2    tuvwxyz_2
3   abcdefghi_3   jklmnopqrs_3    tuvwxyz_3
4   abcdefghi_4   jklmnopqrs_4    tuvwxyz_4
2.99 s ± 278 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
如在dataframe中搜索所示,最优化的方法只需~4秒即可搜索100个值。 而使用索引搜索所有10000个值需要~3秒

另外,如果要查找2个值和1个缺少的值,则需要从相应的字典中查找索引,并使用下面的函数获取公共索引,最后从公共索引列表中获取子集_df

def Get_Common_List_Values(list1, list2):
    if (list1 is None) and (list2 is not None): return list2
    if (list2 is None) and (list1 is not None): return list1

    if (list2 is not None) and (list1 is not None):
        return [row_Index for row_Index in list1 if row_Index in list2]
注意:所有时间都是根据虚拟数据计算的。您的实际时间会有所不同

解决方案1-优化数据帧搜索

输出:

Dummy registry_df size = 217.666774 MB

        A               B             C
0   abcdefghi_0   jklmnopqrs_0    tuvwxyz_0
1   abcdefghi_1   jklmnopqrs_1    tuvwxyz_1
2   abcdefghi_2   jklmnopqrs_2    tuvwxyz_2
3   abcdefghi_3   jklmnopqrs_3    tuvwxyz_3
4   abcdefghi_4   jklmnopqrs_4    tuvwxyz_4
2.99 s ± 278 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>

输出:

11.9 s ± 338 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
11.4 s ± 441 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
13 s ± 756 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
5.57 s ± 384 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
5.22 s ± 122 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
3.99 s ± 140 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
解决方案2-如果您有一点额外的内存,请将索引存储在相应的列字典中

输出:

948 ms ± 64.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
27.7 ms ± 2.47 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
> 创建包含索引的字典

dict_Company_Name ={}
dict_Business_ID = {}
dict_Location = {}

def Create_Dictionary_From_DataFrame(df, dict_Company_Name, dict_Business_ID, dict_Location):
    for row_Index in range(len(df)):
        comany_name, business_id, location = df.iloc[row_Index]
        dict_Company_Name.setdefault(comany_name, []).append(row_Index)
        dict_Business_ID.setdefault(business_id, []).append(row_Index)
        dict_Location.setdefault(location, []).append(row_Index)

%time Create_Dictionary_From_DataFrame(df, dict_Company_Name, dict_Business_ID, dict_Location)

Wall time: 2min 12s

输出:

Dummy registry_df size = 217.666774 MB

        A               B             C
0   abcdefghi_0   jklmnopqrs_0    tuvwxyz_0
1   abcdefghi_1   jklmnopqrs_1    tuvwxyz_1
2   abcdefghi_2   jklmnopqrs_2    tuvwxyz_2
3   abcdefghi_3   jklmnopqrs_3    tuvwxyz_3
4   abcdefghi_4   jklmnopqrs_4    tuvwxyz_4
2.99 s ± 278 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
如在dataframe中搜索所示,最优化的方法只需~4秒即可搜索100个值。 而使用索引搜索所有10000个值需要~3秒

另外,如果要查找2个值和1个缺少的值,则需要从相应的字典中查找索引,并使用下面的函数获取公共索引,最后从公共索引列表中获取子集_df

def Get_Common_List_Values(list1, list2):
    if (list1 is None) and (list2 is not None): return list2
    if (list2 is None) and (list1 is not None): return list1

    if (list2 is not None) and (list1 is not None):
        return [row_Index for row_Index in list1 if row_Index in list2]

注意:所有时间都是在虚拟数据上计算的。您的实际时间会有所不同

当给定一列值为位置时,您是否有可能需要找到两列值?我假设这里有一个唯一的公司名称具有“n”业务ID,并且对于该唯一的业务ID(w.r.t公司名称)有时可能需要“n”位置,但它基于公司名称和位置。然而,它不一定是唯一的,尽管大多数情况下是唯一的(这是一个有效的假设)这有帮助吗?当给定列中的1个值为位置时,是否有可能需要找到2个列值?我在这里的假设是1个唯一的公司名称具有“n”业务ID,并且对于该1个唯一的业务ID(w.r.t公司名称)有时可能需要“n”位置,但它基于公司名称和位置。然而,它不一定是唯一的,尽管大多数情况下是(这是一个有效的假设),但这有帮助吗?