Панды: Используйте метод DataFrameGroupBy.filter (), чтобы выбрать строки DataFrame со значением, превышающим среднее значение соответствующей группы - PullRequest
1 голос
/ 06 ноября 2019

Я изучаю Python и Pandas и делаю некоторые упражнения, чтобы понять, как все работает. У меня следующий вопрос: могу ли я использовать метод GroupBy.filter (), чтобы выбрать строки DataFrame, которые имеют значение (в определенном столбце), превышающее среднее значение соответствующей группы?

Для этого упражненияЯ использую набор данных "планеты", включенный в Seaborn: 1035 строк x 6 столбцов (имена столбцов: "метод", "число", "orbital_period", "масса", "расстояние", "год").

В python:

import pandas as pd
import seaborn as sns

#Load the "planets" dataset included in Seaborn
data = sns.load_dataset("planets")

#Remove rows with NaN in "orbital_period"
data = data.dropna(how = "all", subset = ["orbital_period"])

#Set display of DataFrames for seeing all the columns:
pd.set_option("display.max_columns", 15)

#Group the DataFrame "data" by "method" ()
group1 = data.groupby("method")
#I obtain a DataFrameGroupBy object (group1) composed of 10 groups.
print(group1)
#Print the composition of the DataFrameGroupBy object "group1".
for lab, datafrm in group1:
    print(lab, "\n", datafrm, sep="", end="\n\n")
print()
print()
print()


#Define the filter_function that will be used by the filter method.
#I want a function that returns True whenever the "orbital_period" value for 
#a row is greater than the mean of the corresponding group's mean.
#This could have been done also directly with "lambda syntax" as argument
#of filter().
def filter_funct(x):
    #print(type(x))
    #print(x)
    return x["orbital_period"] > x["orbital_period"].mean()


dataFiltered = group1.filter(filter_funct)
print("RESULT OF THE FILTER METHOD:")
print()
print(dataFiltered)
print()
print()

К сожалению, я получаю следующую ошибку при запуске сценария.

TypeError: filter function returned a Series, but expected a scalar bool

Похоже, что x ["orbital_period"] не ведет себя каквектор, что означает, что он не возвращает единственные значения Series ... достаточно странно, что метод transform () не страдает от этой проблемы. Действительно, в том же наборе данных (подготовленном, как описано выше), если я запускаю следующее:

#Define the transform_function that will be used by the transform() method.
#I want this function to subtract from each value in "orbital_period" the mean
#of the corresponding group.
def transf_funct(x):
    #print(type(x))
    #print(x)
    return x-x.mean()

print("Transform method runs:")
print()
#I directly assign the transformed values to the "orbital_period" column of the DataFrame.
data["orbital_period"] = group1["orbital_period"].transform(transf_funct)
print("RESULT OF THE TRANSFORM METHOD:")
print()
print(data)
print()
print()
print()

Я получаю ожидаемый результат ...

Do DataFrameGroupBy.filter () и DataFrameGroupBy.transform () есть другое поведение? Я знаю, что могу достичь того, чего хочу, многими другими способами, но мой вопрос: есть ли способ добиться того, чего я хочу, используя метод DataFrameGroupBy.filter ()?

1 Ответ

1 голос
/ 06 ноября 2019

Могу ли я использовать DataFrameGroupBy.filter для исключения определенных строк в группе?

Ответ - Нет . DataFrameGroupBy.filter использует логическое значение single для характеристики всей группы. Результатом фильтрации является удаление всей группы, если она характеризуется как False.

DataFrameGroupBy.filter медленный очень , поэтому часто рекомендуется использовать transform для широковещательной передачи единственного значения истинности всем строкам в группе, а затем для поднабора DataFrame 1. . Вот пример удаления целых групп, где среднее значение <= 50. Метод <code>filter медленнее в 100 раз.

import pandas as pd
import numpy as np

N = 10000
df = pd.DataFrame({'grp': np.arange(0,N,1)//10,
                   'value': np.arange(0,N,1)%100})

# With Filter
%timeit df.groupby('grp').filter(lambda x: x['value'].mean() > 50)
#327 ms ± 2.42 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

# With Transform
%timeit df[df.groupby('grp')['value'].transform('mean') > 50]
#2.7 ms ± 39.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

# Verify they are equivalent
(df.groupby('grp').filter(lambda x: x['value'].mean() > 50) 
  == df[df.groupby('grp')['value'].transform('mean') > 50]).all().all()
#True

1 Увеличение производительности достигается за счет того факта, что transform может позволить вам использовать операцию GroupBy, которая реализована в Cython, как в случае mean,Если это не так, filter может быть таким же быстродействующим, если не чуть лучше.


Наконец, поскольку DataFrameGroupBy.transform передает результат всей группе, это правильный инструмент для использованиякогда нужно исключить определенные строки в группе на основе общей характеристики группы .

В приведенном выше примере, если вы хотите сохранить строки в группе выше группы, это означает, что

df[df['value'] > df.groupby('grp')['value'].transform('mean')]
   # Compare          to the mean of the group the row 
   # each row                   belongs to 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...