操作数据框字典

时间:2019-09-05 13:07:29

标签: python pandas

我有以下数据框:

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中的每个数据帧进行操作感到困惑。关于如何最好地与这些小组合作的任何建议?

3 个答案:

答案 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.anyGroupBy.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个,则可以考虑将数据框转换为长格式。