Группировка данных Pandas на основе условий? - PullRequest
0 голосов
/ 24 октября 2018

Я следую предложенным здесь пандам создать новый столбец на основе значений из других столбцов , но все равно получаю ошибку.По сути, мой фрейм данных Pandas имеет много столбцов, и я хочу сгруппировать фрейм данных на основе нового категориального столбца, значение которого зависит от двух существующих столбцов (AMP, Time).

df
df['Time'] = pd.to_datetime(df['Time']) 
#making sure Time column read from the csv file is time object

import datetime as dt
day_1 = dt.date.today()
day_2 = dt.date.today() - dt.timedelta(days = 1)

def f(row):

    if (row['AMP'] > 100) & (row['Time'] > day_1):
        val = 'new_positives'

    elif (row['AMP'] > 100) & (day_2 <= row['Time'] <= day_1):
        val = 'rec_positives'

    elif (row['AMP'] > 100 & row['Time'] < day_2):
        val = 'old_positives'

    else:
        val = 'old_negatives'

    return val

df['GRP'] = df.apply(f, axis=1) #this gives the following error:
TypeError: ("Cannot compare type 'Timestamp' with type 'date'", 'occurred at index 0')

df[(df['AMP'] > 100) & (df['Time'] > day_1)]  #this works fine

df[(df['AMP'] > 100) & (day_2 <= df['Time'] <= day_1)]  #this works fine

df[(df['AMP'] > 100) & (df['Time'] < day_2)]  #this works fine


#df = df.groupby('GRP')  

Я могу выбрать правильные субкадры на основе условий, указанных выше, но когда я применяю вышеуказанную функцию к каждой строке, я получаю ошибку.Как правильно подходить к группировке данных на основе перечисленных условий?

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

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

import numpy as np
import pandas as pd
mydf = pd.DataFrame({'a':np.arange(10),
   'b':np.random.rand(10)})

def f1(row):
    if row['a'] < 5 & row['b'] < 0.5:
        value = 'less'
    elif row['a'] < 5 & row['b'] > 0.5:
        value = 'more'
    else:
        value = 'same'
    return value

mydf['GRP'] = mydf.apply(f1, axis=1)

ypeError: ("unsupported operand type(s) for &: 'int' and 'float'", 'occurred at index 0')

РЕДАКТИРОВАТЬ 2: Как предложено ниже, заключив оператор сравнения в круглые скобки, добился цели в готовом примере.Эта проблема решена.

Тем не менее, я все еще получаю ту же ошибку в моем реальном примере.Кстати, если бы мне пришлось использовать столбец «AMP» с, возможно, другим столбцом в моей таблице, то все работает, и я могу создать df ['GRP'], применив функцию f к каждой строке.Это показывает, что проблема связана с использованием df ['Time'].Но тогда почему я могу выбрать df [(df ['AMP']> 100) & (df ['Time']> day_1)]?Почему это работает в этом контексте, а не когда условие появляется в функции?

Ответы [ 4 ]

0 голосов
/ 24 октября 2018

У вас есть отличный пример, он очень полезен, и вы можете применять фильтры после группового.Это способ без использования маски.

def get_letter_type(letter):
   if letter.lower() in 'aeiou':
       return 'vowel'
   else:
       return 'consonant'


In [6]: grouped = df.groupby(get_letter_type, axis=1)

https://pandas.pydata.org/pandas-docs/version/0.22/groupby.html

0 голосов
/ 24 октября 2018

Исходя из вашего сообщения об ошибке и примера, есть две вещи, которые нужно исправить.Один из них заключается в корректировке скобок для приоритета оператора в вашем последнем выражении elif.Другой - избегать смешивания datetime.date и Timestamp объектов.

Fix 1: изменить это:

elif (row['AMP'] > 100 & row['Time'] < day_2):

на это:

elif (row['AMP'] > 100) & (row['Time'] < day_2):

Эти две строки отличаются тем, что побитовый оператор & имеет приоритет над операторами сравнения < и >, поэтому python пытается вычислить 100 & row['Time'].Полный список приоритетов операторов Python приведен здесь: https://docs.python.org/3/reference/expressions.html#operator-precedence

Fix 2: Замените эти 3 строки:

import datetime as dt
day_1 = dt.date.today()
day_2 = dt.date.today() - dt.timedelta(days = 1)

на эти 2 строки:

day1 = pd.to_datetime('today')
day_2 = day_1 - pd.DateOffset(days=1)
0 голосов
/ 24 октября 2018

Если вам не нужно использовать пользовательскую функцию, то вы можете использовать несколько масок (, несколько похожих на этот пост SO )

Для Time column я использовал этокод.Возможно, вы пытались сравнить Time значения столбца, у которых не было требуемого dtype (это мое предположение)

import datetime as dt
mydf['Time'] = pd.date_range(start='10/14/2018', end=dt.date.today())
day_1 = pd.to_datetime(dt.date.today())
day_2 = day_1 - pd.DateOffset(days = 1)

Вот необработанные данные

mydf

   a         b       Time
0  0  0.550149 2018-10-14
1  1  0.889209 2018-10-15
2  2  0.845740 2018-10-16
3  3  0.340310 2018-10-17
4  4  0.613575 2018-10-18
5  5  0.229802 2018-10-19
6  6  0.013724 2018-10-20
7  7  0.810413 2018-10-21
8  8  0.897373 2018-10-22
9  9  0.175050 2018-10-23

Один из подходов заключается в использовании масок для столбцов

# Append new column
mydf['GRP'] = 'same'
# Use masks to change values in new column
mydf.loc[(mydf['a'] < 5) & (mydf['b'] < 0.5) & (mydf['Time'] < day_2), 'GRP'] = 'less'
mydf.loc[(mydf['a'] < 5) & (mydf['b'] > 0.5) & (mydf['Time'] > day_1), 'GRP'] = 'more'
mydf

   a         b       Time   GRP
0  0  0.550149 2018-10-14  same
1  1  0.889209 2018-10-15  same
2  2  0.845740 2018-10-16  same
3  3  0.340310 2018-10-17  less
4  4  0.613575 2018-10-18  same
5  5  0.229802 2018-10-19  same
6  6  0.013724 2018-10-20  same
7  7  0.810413 2018-10-21  same
8  8  0.897373 2018-10-22  same
9  9  0.175050 2018-10-23  same

Другой подход заключается в задании a, b и Time в качестве мультииндекса и использовании на основе индексамаски для установки значений

mydf.set_index(['a','b','Time'], inplace=True)

# Get Index level values
a = mydf.index.get_level_values('a')
b = mydf.index.get_level_values('b')
t = mydf.index.get_level_values('Time')

# Apply index-based masks
mydf['GRP'] = 'same'
mydf.loc[(a < 5) & (b < 0.5) & (t < day_2), 'GRP'] = 'less'
mydf.loc[(a < 5) & (b > 0.5) & (t > day_1), 'GRP'] = 'more'
mydf.reset_index(drop=False, inplace=True)
mydf

   a         b       Time   GRP
0  0  0.550149 2018-10-14  same
1  1  0.889209 2018-10-15  same
2  2  0.845740 2018-10-16  same
3  3  0.340310 2018-10-17  less
4  4  0.613575 2018-10-18  same
5  5  0.229802 2018-10-19  same
6  6  0.013724 2018-10-20  same
7  7  0.810413 2018-10-21  same
8  8  0.897373 2018-10-22  same
9  9  0.175050 2018-10-23  same

Источник в Фильтр по дате и времени и создают диапазон дат .

0 голосов
/ 24 октября 2018

В скобки if необходимо добавить несколько скобок:

import numpy as np
import pandas as pd

mydf = pd.DataFrame({'a':np.arange(10),
   'b':np.random.rand(10)})

def f1(row):
    if (row['a'] < 5) & (row['b'] < 0.5):
        value = 'less'
    elif (row['a'] < 5) & (row['b'] > 0.5):
        value = 'more'
    else:
        value = 'same'
    return value

mydf['GRP'] = mydf.apply(f1, axis=1)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...