我有以下数据框:
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
我正在尝试搜索每个“组”,以查看任一“数字”列中的任何数字是否在某个范围内。如果该范围内的组中存在一个值,我想将组中的 ALL 名称附加到列表中。一个很大的障碍是Number列可以包含偶然的字符串,并且对它们的处理方式与超出范围的数字相同。
在此示例中,我们将范围定为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中的每个数据帧进行操作感到困惑。关于如何最好地与这些小组合作的任何建议?
答案 0 :(得分:2)
您的列中有一些无效值,必须将其转换为有效的数字值才能执行有效的比较。您在这里有几个选择,可以只使用pandas
个操作,然后执行慢一点的groupby
,也可以降到numpy
以获得非常有效的解决方案。
选项1
stack
+ unstack
+ groupby
+ transform
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
使用numpy
和一些遮罩的更快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)
答案 1 :(得分:2)
使用wide_to_long
进行整形,然后使用GroupBy.any
和GroupBy.transform
对每个组进行测试,因此可能使用过滤器列Name
:
df = pd.wide_to_long(df.reset_index(),['Name','Number'],i=['index','Group'],j='drop')
s = pd.to_numeric(df['Number'], errors='coerce').between(200, 300)
L = df.loc[s.groupby(level=1).transform('any'), 'Name'].tolist()
print (L)
['B', 'Y', 'Y', 'L', 'F', 'D', 'H', 'G', 'X', 'Q']
详细信息:
print (df)
Name Number
index Group drop
0 1 1 R 1
2 G 5
1 2 1 B EXP
2 Y 9
2 2 1 Y 225
2 L 185
3 2 1 F 17
2 D 2
4 3 1 H 259
2 G 175
5 3 1 X 172
2 Q EXP
答案 2 :(得分:1)
类似于克里斯的回答,但没有 CustomObject object = new CustomObject (1,DateTime.Now,DateTime.Now);
string s = JsonConvert.SerializeObject(object);
DoDragDrop(s, DragDropEffects.Copy);
Text = DateTime.Now.ToString();
/ CustomObject object = new CustomObject (1,DateTime.Now,DateTime.Now);
DoDragDrop(object , DragDropEffects.Copy);
Text = DateTime.Now.ToString();
stack
给予:
unstack
注意:如果名称/数字列超过2个,则可以考虑将数据框转换为长格式。