#python #pandas
#python #pandas
Вопрос:
Я новичок в Python Pandas и, следовательно, не могу найти синтаксический эквивалент многих обычных операций SQL. Учитывая сценарий игрушки:
id rank ts alive
1 1 2015-11-01 1
1 2 2015-11-03 1
1 3 2015-11-07 1
2 1 2015-11-03 1
2 2 2015-11-08 1
Как бы я добился следующего:
id rank ts alive cumulative_age_in_days mean_id_age_on_this_date
1 1 2015-11-01 1 0 0
1 2 2015-11-03 1 2 1
1 3 2015-11-07 1 6 5
2 1 2015-11-03 1 0 1
2 2 2015-11-08 1 5 6
где cumulative_day_age
— дата текущей строки минус самая ранняя дата для идентификатора. Например, on 2015-11-03
, id=1
составляет 2 дня с момента его первого наблюдения 2015-11-01
. Включено 2015-11-07
, ему 6 дней ( 2015-11-07
— 2015-11-01
).
и где mean_id_age_on_this_date
средний возраст всего id
на дату этой строки, если id
имеет alive = 1
. Так что для 2015-11-03
, id=1
2 дня, но id=2
0 дней, так mean_id_age_on_this_date
что (0 2)/2 = 1.
Эти два столбца легко сделать в SQL, но мне не хватает знакомства с Python Pandas в той же степени, так что это невероятно сложная задача. Любые подсказки, код или предложения приветствуются.
Ответ №1:
Сначала вычтите первый минимальный день для групп GroupBy.transform
с min
помощью, а затем выведите timedeltas, преобразуйте в дни Series.dt.days
, затем преобразуйте значения, не соответствующие df['alive'].eq(1)
ошибочным значениям, Series.where
и используйте GroupBy.transform
с mean
:
df['ts'] = pd.to_datetime(df['ts'])
df['cumulative_age_in_days'] = df['ts'].sub(df.groupby('id')['ts'].transform('min')).dt.days
df['mean_id_age_on_this_date'] = (df['cumulative_age_in_days'].where(df['alive'].eq(1))
.groupby(df['ts'])
.transform('mean'))
print (df)
id rank ts alive cumulative_age_in_days
0 1 1 2015-11-01 1 0
1 1 2 2015-11-03 1 2
2 1 3 2015-11-07 1 6
3 2 1 2015-11-03 1 0
4 2 2 2015-11-08 1 5
mean_id_age_on_this_date
0 0
1 1
2 6
3 1
4 5
Ответ №2:
Используйте pd.to_datetime
и Groupby.transform
:
In [1538]: df['ts'] = pd.to_datetime(df['ts']) # Convert `ts` to `datetime`
In [1547]: df['cumulative_age_in_days'] = df.ts.dt.day - df.groupby('id')['ts'].transform('min').dt.day
In [1556]: df['mean_id_age_on_this_date'] = df[df.alive.eq(1)].groupby('ts')['cumulative_age_in_days'].transform('mean')
In [1557]: df
Out[1557]:
id rank ts alive cumulative_age_in_days mean_id_age_on_this_date
0 1 1 2015-11-01 1 0 0
1 1 2 2015-11-03 1 2 1
2 1 3 2015-11-07 1 6 6
3 2 1 2015-11-03 1 0 1
4 2 2 2015-11-08 1 5 5
Ответ №3:
def converDate(string):
return datetime.strptime(string, "%Y-%m-%d")
def getEarly(data):
min_date = sorted(data["ts"].map(converDate))[0]
data["cumulative_age_in_days"] = data["ts"].map(lambda el : (converDate(el) - min_date).days)
return data
def getMean(data):
data["mean_id_age_on_this_date"] = int(sum(data["cumulative_age_in_days"]) / len(data))
return data
data1 = data.groupby("id").apply(getEarly)
data2 = data1.groupby("ts").apply(getMean)
data2