Python:迭代数据框列,检查存储在数组中的条件值,并将值获取到列表

时间:2017-01-09 10:30:17

标签: python arrays pandas dataframe

在论坛上得到一些帮助后,我设法做了我想要的事情,现在我需要进入下一个级别。 (详细解释如下: Python Data Frame: cumulative sum of column until condition is reached and return the index):

我有一个数据框:

In [3]: df
Out[3]: 
   index  Num_Albums  Num_authors
0      0          10            4
1      1           1            5
2      2           4            4
3      3           7         1000
4      4           1           44
5      5           3            8

我添加了一列,其中包含另一列的累积总和。

In [4]: df['cumsum'] = df['Num_Albums'].cumsum()

In [5]: df
Out[5]: 
   index  Num_Albums  Num_authors  cumsum
0      0          10            4      10
1      1           1            5      11
2      2           4            4      15
3      3           7         1000      22
4      4           1           44      23
5      5           3            8      26

然后我将一个条件应用于cumsum列,并使用给定的容差提取满足条件的行的相应值:

In [18]: tol = 2

In [19]: cond = df.where((df['cumsum']>=15-tol)&(df['cumsum']<=15+tol)).dropna()

In [20]: cond
Out[20]: 
   index  Num_Albums  Num_authors  cumsum
2    2.0         4.0          4.0    15.0

现在,我想要做的是替换示例中的条件15,条件存储在数组中。检查条件何时满足并且不检索整行,而只检索列Num_Albums的值。最后,所有这些检索到的值(每个条件一个)存储在数组或列表中。 来自matlab,我会做这样的事情(我为这个混合的matlab / python语法道歉):

conditions = np.array([10, 15, 23])
for i=0:len(conditions)
   retrieved_values(i) = df.where((df['cumsum']>=conditions(i)-tol)&(df['cumsum']<=conditions(i)+tol)).dropna()

因此,对于上面的数据框,我会得到(tol=0):

retrieved_values = [10, 4, 1]

我想要一个解决方案,让我尽可能保留.where功能..

2 个答案:

答案 0 :(得分:2)

输出并不总是1个数字对吗? 如果输出是精确的1号,你可以写这段代码

tol = 0
#condition
c = [5,15,25]
value = []

for i in c:
    if len(df.where((df['a'] >= i - tol) & (df['a'] <= i + tol)).dropna()['a']) > 0:
        value = value + [df.where((df['a'] >= i - tol) & (df['a'] <= i + tol)).dropna()['a'].values[0]]
    else:
        value = value + [[]]
print(value)

输出应该像

  

[1,2,3]

如果输出可以是多个数字并且想要像这样

  

[[1.0,5.0],[12.0,15.0],[25.0]]

您可以使用此代码

tol = 5
c = [5,15,25]
value = []

for i in c:
    getdatas = df.where((df['a'] >= i - tol) & (df['a'] <= i + tol)).dropna()['a'].values
    value.append([x for x in getdatas])
print(value)

答案 1 :(得分:2)

一个快速的方法是利用NumPy的广播技术作为this answer来自相同帖子链接的扩展,尽管实际上询问了与使用DF.where相关的答案

广播消除了迭代数组中每个元素的需要,同时它也非常高效。

这篇文章的唯一补充是使用np.argmax来获取每列的第一个True实例的索引(遍历↓方向)。

conditions = np.array([10, 15, 23])
tol = 0
num_albums = df.Num_Albums.values
num_albums_cumsum = df.Num_Albums.cumsum().values
slices = np.argmax(np.isclose(num_albums_cumsum[:, None], conditions, atol=tol), axis=0)

检索切片:

slices
Out[692]:
array([0, 2, 4], dtype=int64)

生成相应的数组:

num_albums[slices]
Out[693]:
array([10,  4,  1], dtype=int64)

如果您仍然喜欢使用DF.where,则使用list-comprehension -

是另一种解决方案
[df.where((df['cumsum'] >= cond - tol) & (df['cumsum'] <= cond + tol), -1)['Num_Albums']
   .max() for cond in conditions]
Out[695]:
[10, 4, 1]

不满足给定标准的条件将替换为-1。这样做可以在最后保留dtype