操作 pandas 数据框值的有效方法
Efficient way to manipulate values of a pandas dataframe
我正在处理 2 个巨大的数据帧,我需要执行一个特定的操作来为第一个数据帧中的每个唯一 ID 检索两个数据帧之一的最频繁值。我会用一个例子更好地解释它。
假设我要数据帧,第一个将被称为 df_id
,第二个将被称为 df_values
df_values:
ids values
0 id1 10
1 id2 20
2 id1 10
3 id1 30
4 id2 40
...
df_id:
ids desc
0 id1 a product
1 id2 a product
2 id3 a product
在真实的数据框中,我有额外的列,但为了清楚起见,我省略了它们。
现在,df_id
包含我需要的所有 ID 的引用,而 df_values
包含与每个 ID 关联的(多个)值。
我的工作范围是创建一个字典,为每个不同的 ID 报告最常见的值。如果它没有出现在 df_values
中,那么我写一个 None
而不是一个值。
values_dict
{'id1': 10, 'id2': 20, 'id3': None}
我试图通过类似的方式解决这个问题:
from collections import Counter
import numpy as np
def Most_Common(lst):
data = Counter(lst)
return data.most_common(1)[0][0]
dict_val = {}
for ar in pd.unique(df_id['ids']):
df_art = df_values.loc[df_values['ids'] == ar]
print("Done", ar)
val = Most_Common(df_art['values']) if not df_art.empty else None
dict_val[ar] = val
来自 this answer
的 Most_Common
函数代码
但是,如果我的数据帧非常大(我就是这种情况),此解决方案似乎无法很好地升级。我什至尝试使用 multiprocessing
库:
from collections import Counter
import multiprocessing as mp
import numpy as np
dict_val = {}
unique_ids = pd.unique(df_id["ids"])
unique_ids = np.array_split(unique_ids, 5)
def register_value(ids):
for ar in ids:
df_art = df_values.loc[df_values['ids'] == ar]
print("Done", ar)
val = Most_Common(df_art['values']) if not df_art.empty else None
dict_val[ar] = val
with mp.Pool(processes = 5) as p:
p.map(register_value, unique_ids)
但代码仍然 运行 大约 40 分钟...也许我做错了什么。是否有一个有效的解决方案,也可以在多处理的情况下应用?谢谢。
我的建议:
在 df_values 中查找最常见的值,按 ID 分组。如果有多个最频繁的值,取第一个:
most_freq = df_values.groupby('ids').agg(lambda x: pd.Series.mode(x)[0])['values'].to_dict()
根据 df_id 中的 id 创建一个字典,并将 None 分配给每个索引:
dict_val = dict.fromkeys(df_id['ids'])
用第一个字典更新第二个字典。所有 'None' 将替换为最常见的值:
dict_val.update(most_freq)
输出:
{'id1': 10, 'id2': 20, 'id3': None}
这只是一个样本,所以很难猜测它能提高多少性能。它应该快得多,因为我们没有遍历所有元素。请检查并告诉我。
我正在处理 2 个巨大的数据帧,我需要执行一个特定的操作来为第一个数据帧中的每个唯一 ID 检索两个数据帧之一的最频繁值。我会用一个例子更好地解释它。
假设我要数据帧,第一个将被称为 df_id
,第二个将被称为 df_values
df_values:
ids values
0 id1 10
1 id2 20
2 id1 10
3 id1 30
4 id2 40
...
df_id:
ids desc
0 id1 a product
1 id2 a product
2 id3 a product
在真实的数据框中,我有额外的列,但为了清楚起见,我省略了它们。
现在,df_id
包含我需要的所有 ID 的引用,而 df_values
包含与每个 ID 关联的(多个)值。
我的工作范围是创建一个字典,为每个不同的 ID 报告最常见的值。如果它没有出现在 df_values
中,那么我写一个 None
而不是一个值。
values_dict
{'id1': 10, 'id2': 20, 'id3': None}
我试图通过类似的方式解决这个问题:
from collections import Counter
import numpy as np
def Most_Common(lst):
data = Counter(lst)
return data.most_common(1)[0][0]
dict_val = {}
for ar in pd.unique(df_id['ids']):
df_art = df_values.loc[df_values['ids'] == ar]
print("Done", ar)
val = Most_Common(df_art['values']) if not df_art.empty else None
dict_val[ar] = val
来自 this answer
的Most_Common
函数代码
但是,如果我的数据帧非常大(我就是这种情况),此解决方案似乎无法很好地升级。我什至尝试使用 multiprocessing
库:
from collections import Counter
import multiprocessing as mp
import numpy as np
dict_val = {}
unique_ids = pd.unique(df_id["ids"])
unique_ids = np.array_split(unique_ids, 5)
def register_value(ids):
for ar in ids:
df_art = df_values.loc[df_values['ids'] == ar]
print("Done", ar)
val = Most_Common(df_art['values']) if not df_art.empty else None
dict_val[ar] = val
with mp.Pool(processes = 5) as p:
p.map(register_value, unique_ids)
但代码仍然 运行 大约 40 分钟...也许我做错了什么。是否有一个有效的解决方案,也可以在多处理的情况下应用?谢谢。
我的建议:
在 df_values 中查找最常见的值,按 ID 分组。如果有多个最频繁的值,取第一个:
most_freq = df_values.groupby('ids').agg(lambda x: pd.Series.mode(x)[0])['values'].to_dict()
根据 df_id 中的 id 创建一个字典,并将 None 分配给每个索引:
dict_val = dict.fromkeys(df_id['ids'])
用第一个字典更新第二个字典。所有 'None' 将替换为最常见的值:
dict_val.update(most_freq)
输出:
{'id1': 10, 'id2': 20, 'id3': None}
这只是一个样本,所以很难猜测它能提高多少性能。它应该快得多,因为我们没有遍历所有元素。请检查并告诉我。