我有以下数据框:
Name1 Number1 Name2 Number2 Group
R 1 G 5 1
B EXP Y 9 2
Y 225 L 185 2
F 17 D 2 2
H 259 G 175 3
X 172 Q EXP 3
我试着在每个“组”中搜索,看看每个数字列中的任何数字是否在某个范围内。如果在该范围内存在组中的一个值,则我希望将组中的所有名称追加到列表中。一个很大的障碍是数字列可以包含偶尔出现的字符串,这些字符串的处理方式与超出范围的数字相同。
在这个例子中,我们会说范围是200-300
搜索组后得到的列表将是:
L = [B,Y,Y,L,F,D,H,G,X,Q]
请注意,列表中未包含组1中的名称,因为组1在指定范围内的Number1/Number2列中不包含任何值。
我的代码:
newList = {}
dict_of_groups = {k: v for k, v in df.groupby('Group')}
for df in dict_of_groups.values()
if df[df['Number1'] | df['Number2'] > 199]: #how do I specify AND < 300 here?
a = df['Number1'].values.tolist()
b = df['Number2'].values.tolist()
newList.update(a,b)
我对如何有效地操作dict-of-dataframes中的每个数据帧有点困惑。关于如何最好地与这些团队合作有什么建议吗?
最佳答案
列中有一些无效值,必须将这些值转换为有效的数值才能执行有效的比较。这里有两个选项,您可以只使用pandas
操作,执行较慢的groupby
,也可以下拉到numpy
以获得非常有效的解决方案。
选择1stack
+unstack
+groupby
+transform
+numpy
names = df.filter(like='Name').to_numpy()
m = (pd.to_numeric(df.filter(like='Number').stack(), errors='coerce')
.between(200, 300).unstack())
mask = m.groupby(df['Group']).transform('any').any(1)
names[mask].ravel().tolist()
['B', 'Y', 'Y', 'L', 'F', 'D', 'H', 'G', 'X', 'Q']
选择2
使用
np.add.at
和一些掩蔽的快速解决方案a = df.filter(like='Name').to_numpy().ravel()
b = df.filter(like='Number').to_numpy().ravel()
c = np.repeat(df['Group'].to_numpy(), a.shape[0] // df.shape[0])
n = pd.to_numeric(b, errors='coerce')
f = np.zeros(c.max()+1, dtype=int)
m = np.logical_and(n >= 200, n <= 300)
np.add.at(f, c, m)
mask = f[c].astype(bool)
a[mask]
array(['B', 'Y', 'Y', 'L', 'F', 'D', 'H', 'G', 'X', 'Q'], dtype=object)
时间安排
df = pd.concat([df]*1000, ignore_index=True)
%timeit chris_stack()
22.7 ms ± 1.86 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit chris_numpy()
11.9 ms ± 153 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\
%timeit quang()
16.7 ms ± 101 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit jezrael()
78.5 ms ± 685 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
关于python - 操作数据框字典,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57806220/