Найдите первую строку, которая удовлетворяет условиям, используя массив Numpy или Pandas фрейм данных. (возможно сложно) - PullRequest
0 голосов
/ 05 апреля 2020

Я задам вопрос в библиотечной манере c, так как один может быть лучше другого в этом случае. Или, может быть, существует другая волшебная библиотека?

У меня есть таблица БД, содержащая около 10000 записей, и я знаю, как создать из нее массив numpy или фрейм данных. Данные примерно такие.

   ...
   20,25,1,5
   20,25,2,3
   20,25,4,21
   20,25,5,1
   20,25,9,19
   ...
   45,47,6,20
   45,47,10,2
   45,47,11,56
   45,47,21,41
   ...

В приведенных ниже примерах критериев поиска я следую за значением '20' в столбце col4 этой строки.

45,47,6,20
  1. Обратите внимание на первое 2 столбца имеют одинаковые значения и определяют группу.
  2. Col2 всегда будет> = col1 в строке.
  3. Значения в col3 всегда будут в порядке возрастания внутри группы, а не обязательно смежный.

Я следую за значением ячейки в col4, используя следующие критерии поиска.

Я знаю, как использовать маску в numpy, чтобы найти все строки значения которого, например, 'col1> = 45 AND col2 <= 47'. У меня есть третье значение поиска, например, '8', которое должно использоваться для поиска col3 в вышеуказанной группе (col1, col2, 45 -> 47)

Мне нужно найти первую строку, чья значение в col3 <= 8. </strong>

Поэтому мне нужно искать строки, у которых 'col1> = 45 AND col2 <= 47' в последовательности col3 DESCENDING до строки '45, 47,6, 20 'найдено. Я после значения '20' в col4. </p>

Всегда будет только одна строка, которая будет соответствовать. Вполне возможно, что ни одна строка не будет соответствовать критериям (например, если значение поиска в столбце col3 было равно 3).

Мне нужно выполнять 100 с 1000 поисков за раз, поэтому я бы предпочел, чтобы не было новых массивов или фреймов данных. создано, если это не оказывает минимального влияния на ресурсы.

Ответы [ 2 ]

1 голос
/ 05 апреля 2020

Я бы:

  1. отфильтровал кадр данных, чтобы сохранить только строки, соответствующие критериям
  2. сгруппировать по первым двум столбцам
  3. применить tail(1) к каждой группе чтобы найти соответствующую строку для каждой группы, если любой

код будет:

df[(df['col1']>=45)&(df['col2']<=47)&(df['col3']<=8)].groupby(['col1', 'col2']
                                                              ).tail(1)

Для вашего образца он дает ожидаемый результат

   col1  col2  col3  col4
5    45    47     6    20

. Хорошей новостью является то, что вы можете искать несколько групп за один проход, и это все равно дает ожидаемые результаты, если ни одна строка не соответствует критериям. Демо:

>>> df[(df['col1']>=20)&(df['col2']<=47)&(df['col3']<=8)].groupby(['col1', 'col2']).tail(1)
   col1  col2  col3  col4
3    20    25     5     1
5    45    47     6    20
>>> df[(df['col1']>=20)&(df['col2']<=47)&(df['col3']<=3)].groupby(['col1', 'col2']).tail(1)
   col1  col2  col3  col4
1    20    25     2     3
>>> df[(df['col1']>=45)&(df['col2']<=47)&(df['col3']<=3)].groupby(['col1', 'col2']).tail(1)
Empty DataFrame
Columns: [col1, col2, col3, col4]
Index: []
1 голос
/ 05 апреля 2020

Я предлагаю использовать мультииндекс для трех первых столбцов и маску для этого мультииндекса следующим образом:

# I reproduce a similar dataframe
import pandas as pd
import numpy as np
np.random.seed(123)
v1 = np.random.randint(0, 10, 10)
v2 = v1 + 2
v3 = np.random.randint(0, 10, 10)
v4 = np.random.randint(0, 10, 10)
df = pd.DataFrame({"v1": v1,
                   "v2": v2,
                   "v3": v3,
                   "v4": v4})
# and sort it according to your comments
df = df.sort_values(by=["v1", "v2", "v3"])
df.head()

Я получаю следующий кадр данных:

  v1  v2  v3  v4
8   0   2   4   0
7   1   3   0   8
9   1   3   1   7
3   1   3   9   4
1   2   4   0   3

# parameters for research
val1 = 1 # the equivalent of your 45
val2 = 3 # the equivalent of your 47
val3 = 2 # the equivalent of your 8

# Set the multiindex
hdf = df.set_index(["v1", "v2", "v3"]).sort_index(ascending=False)
hdf.tail()

Ваш Теперь фрейм данных выглядит следующим образом:

          v4
v1 v2 v3    
2  4  0    3
1  3  9    4
      1    7
      0    8
0  2  4    0
# Define the mask
mask = (hdf.index.get_level_values("v1") >= val1) & \
        (hdf.index.get_level_values("v2") <= val2) &\
        (hdf.index.get_level_values("v3") <= val3)

# Select only the first row returned by the selection using cumsum on mask
print(hdf.loc[mask & (mask.cumsum() == 1), ["v4"]])

И вы получите:

          v4
v1 v2 v3    
1  3  1    7
...