#python #pandas #pivot-table
#python #pandas #сводная таблица
Вопрос:
Я хочу разделить каждый месяц внутри периода между столбцами «начало» и «конец», чем я знаю, что могу использовать сводную таблицу, чтобы сделать их столбцами:
subscription|values| start | end
x |1 |5/5/2018 |6/5/2018
y |2 |5/5/2018 |8/5/2018
z |1 |5/5/2018 |9/5/2018
a |3 |5/5/2018 |10/5/2018
b |4 |5/5/2018 |11/5/2018
c |2 |5/5/2018 |12/5/2018
Желаемый результат:
subscription|jan| feb | mar | abr | jun | jul | aug | sep | out | nov | dez
x | | | | | 1 | 1 | | | | |
y | | | | | 2 | 2 | 2 | | | |
z | | | | | 1 | 1 | 1 | 1 | | |
a | | | | | 3 | 3 | 3 | 3 | 3 | |
b | | | | | 4 | 4 | 4 | 4 | 4 | 4 |
c | | | | | 2 | 2 | 2 | 2 | 2 | 2 | 2
Комментарии:
1. Что вы уже пробовали?
2. сделал разницу между концом и началом df[‘dif’]=df[‘end’]-df[‘start’] также попытался сгенерировать сводную таблицу даже без месяцев df3 = pd.сводная таблица(df, значения=’values’, индекс=’subscription’, столбцы =’dif’)
3. Не очень полезно 😉 Наивным подходом было бы создавать новый столбец для каждого месяца, а затем устанавливать значение этого столбца в зависимости от того, находится ли этот месяц между «концом» и «началом». Вот несколько указателей:
DataFrame.assign
для создания столбцов,Series.where
для установки значений на основе условия,Series.between
для проверки того, что значение находится между двумя другими значениями,pandas.Timestamp
для создания дат.
Ответ №1:
Используя простой pd.Series.cumsum
import calendar
df2 = pd.DataFrame(np.zeros(shape=[len(df),13]),
columns=map(lambda s: calendar.month_abbr[s],
np.arange(13)))
Первый набор начинается как значения и заканчивается как -values
.
r = np.arange(len(df))
df2.values[r, df.start.dt.month] = df['values']
df2.values[r, df.end.dt.month] = -df['values']
Затем cumsum
через axis=1
df2 = df2.cumsum(1)
Установите конечное значение в values
df2.values[r, df.end.dt.month]= df['values']
Конечный результат:
Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
0 0 0 0 0 0 1 1 0 0 0 0 0 0
1 0 0 0 0 0 2 2 2 2 0 0 0 0
2 0 0 0 0 0 1 1 1 1 1 0 0 0
3 0 0 0 0 0 3 3 3 3 3 3 0 0
4 0 0 0 0 0 4 4 4 4 4 4 4 0
5 0 0 0 0 0 2 2 2 2 2 2 2 2
Комментарии:
1. это очень хорошо, спасибо. Я просто забыл упомянуть, что в моей реальной базе данных период во многих случаях равен 1 году или более. таким образом, в этих случаях значения сталкиваются и становятся отрицательными. Вы знаете, как это решить?
2. @RicardoFernandes Каков результат в этом случае?
Ответ №2:
Метод из sklearn
MultiLabelBinarizer
from sklearn.preprocessing import MultiLabelBinarizer
df['L'] = [pd.date_range(x, y, freq='M') for x, y in zip(df.start, df.end)]
mlb = MultiLabelBinarizer()
yourdf=pd.DataFrame(mlb.fit_transform(df['L']),columns=mlb.classes_, index=df.index).mul(df['values'],0)
yourdf.columns=yourdf.columns.strftime('%Y%B')
yourdf['subscription']=df['subscription']
yourdf
Out[75]:
2018May 2018June ... 2018November subscription
0 1 0 ... 0 x
1 2 2 ... 0 y
2 1 1 ... 0 z
3 3 3 ... 0 a
4 4 4 ... 0 b
5 2 2 ... 2 c
[6 rows x 8 columns]
Комментарии:
1. что такое df[‘L]?