Для заданного ввода верните строку, которая имеет значение диапазона, содержащего этот вход - PullRequest
0 голосов
/ 01 ноября 2019

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

Итак, у меня есть фрейм данных Pandas с многоуровневым индексированием.

TEST     Gender     Age     Category     Level     Points     Curl Ups
IST      Female     20-24   Outstanding  High      100        105-500
                            Outstanding  Medium    95         103-104
                            Outstanding  Low       90         100-102
...       ...       ...         ...        ...      ...        ...
                    25-29   Outstanding  High      100        103-500
                            Outstanding  Medium    95         100-102
...

Я хочубыть в состоянии ввести данные для теста, пол, возраст и количество сверток, которые сделал человек, т.е. для теста IST, женщина, которая была 26 лет и сделала 100 сверток, выглядела бы как

['IST','Female',26,100]

Результат, который я ищу, был бы точками на уровне категории. Т.е.;

[95, 'Outstanding-Medium']

Таким образом, он должен быть в состоянии принять 26 для ввода 'Age' и знать, что нужно переходить к строкам, которые попадают под блок 25-29, а затем принимать ввод100 и знать, чтобы вытащить строку, в которую попадает 100, т.е. 100-102. Они включают в себя (от 100 до 102 включительно Curl Ups в возрасте 26 лет дают вам 95 баллов, что является выдающимся средством).

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

Что мне нужно, вы даете ему значение, оно вытягивает строку с диапазоном, содержащим это значение.

1 Ответ

0 голосов
/ 01 ноября 2019

Это не совсем конкретный ответ, но я думаю, что эта общая идея может сработать для вас. Идея состоит в том, чтобы создать новые столбцы в кадре данных, которые обозначают минимум и максимум каждого значения диапазона. Тогда вы можете довольно просто отфильтровать кадр данных на основе этих значений:

import numpy as np
import pandas as pd

df = pd.DataFrame()
df['Curl Ups'] = ['100-500', '100-300', '200-300']
df['Age'] = ['20-24', '25-29', '30-34']
df['Points'] = [50, 60, 70]
df['Category'] = ['Decent', 'Average', 'Good']

# Create new min & max columns
df['min_curlups'] = [int(x[:x.index('-')]) for x in df['Curl Ups']]
df['max_curlups'] = [int(x[x.index('-')+1:]) for x in df['Curl Ups']]

df['min_age'] = [int(x[:x.index('-')]) for x in df['Age']]
df['max_age'] = [int(x[x.index('-')+1:]) for x in df['Age']]

# Filter by contestant's value being within the range
num_curlups = 200
filtered_df = df.loc[(df['min_curlups'] < num_curlups) & (num_curlups < df['max_curlups'])]
print(filtered_df[['Points', 'Category']])

РЕДАКТИРОВАТЬ

Я пропустил многоиндексную часть ранее. На самом деле, я никогда не слышал об этой функциональности в Pandas. Ура для изучения новых вещей! Вот решение, которое, кажется, работает и, надеюсь, не требует особых настроек для вашего использования:

Во-первых, настройте тестовый DataFrame и добавьте в столбцы, которые мой метод нуждается в фильтрации:

import numpy as np
import pandas as pd

df = pd.DataFrame(index=[np.array(['IST', 'IST', 'IST', 'IST', 'ELSE', 'ELSE']),np.array(['Female', 'Male', 'Female', 'Male', 'Female', 'Male'])])
df.index.names = ['TEST', 'Gender']
df['Curl Ups'] = ['100-700', '100-300', '100-300', '100-300', '200-300', '400-500']
df['Age'] = ['20-24', '25-29', '30-34', '20-24', '30-34', '20-24']
df['Points'] = [90, 60, 70, 80, 70, 80]
df['Category'] = ['Outstanding', 'Average', 'Good', 'Better-than-me', 'Good', 'Better-than-me']
df['Level'] = ['Low', 'Medium', 'High', 'Low', 'Medium', 'High']

# Create 'Category-Level' combined column
df['Category-Level'] = df['Category'] + '-' + df['Level']

# Create new min & max columns
df['min_Curl Ups'] = [int(x[:x.index('-')]) for x in df['Curl Ups']]
df['max_Curl Ups'] = [int(x[x.index('-')+1:]) for x in df['Curl Ups']]

df['min_Age'] = [int(x[:x.index('-')]) for x in df['Age']]
df['max_Age'] = [int(x[x.index('-')+1:]) for x in df['Age']]

df

А вот функция, которая должна принимать входные данные, аналогичные требуемым, и выводить необходимую информацию:

def filter_multiindex_df( df, inputs, input_fields=['TEST', 'Gender', 'Age', 'Curl Ups'], outputs=['Points', 'Category-Level'] ):

    # Pull out the inputs corresponding to multi-level indices & filter to get the DF cross-section
    input_idx = [i for i,x in enumerate(input_fields) for j,y in enumerate(df.index.names) if x == y]
    index_inputs = [inputs[i] for i in input_idx]
    filt_df = df.xs(index_inputs)

    # Filter based on the rest of the inputs that weren't indices
    for i, field in enumerate(input_fields):
        if i not in input_idx:
            filt_df = filt_df.loc[ (filt_df['min_'+field] <= inputs[i]) & (inputs[i] <= filt_df['max_'+field])]

    return filt_df[outputs].values[0]


# Test the function    
print(filter_multiindex_df(df, inputs=['IST', 'Female', 22, 100]))
...