Добавить недостающие строки на основе столбца

#python #pandas #missing-data

#python #панды #отсутствует-данные

Вопрос:

Я дал следующий df

 df = pd.DataFrame(data = {'day': [1, 1, 1, 2, 2, 3], 'pos': 2*[1, 14, 18], 'value': 2*[1, 2, 3]}    
df
  
     day pos value
0   1   1   1
1   1   14  2
2   1   18  3
3   2   1   1
4   2   14  2
5   3   18  3
  

и я хочу заполнить строки так, чтобы каждый день имел все возможные значения столбца ‘pos’

желаемый результат:

     day pos value
0   1   1   1.0
1   1   14  2.0
2   1   18  3.0
3   2   1   1.0
4   2   14  2.0
5   2   18  NaN
6   3   1   NaN
7   3   14  NaN
8   3   18  3.0
  

Предложение:

 df.set_index('pos').reindex(pd.Index(3*[1,14,18])).reset_index()
  

дает:

 ValueError: cannot reindex from a duplicate axis
  

Ответ №1:

Давайте попробуем pivot тогда stack :

 df.pivot('day','pos','value').stack(dropna=False).reset_index(name='value')
  

Вывод:

    day  pos  value
0    1    1    1.0
1    1   14    2.0
2    1   18    3.0
3    2    1    1.0
4    2   14    2.0
5    2   18    NaN
6    3    1    NaN
7    3   14    NaN
8    3   18    3.0
  

Вариант 2: объединить с MultiIndex:

 df.merge(pd.DataFrame(index=pd.MultiIndex.from_product([df['day'].unique(), df['pos'].unique()])),
         left_on=['day','pos'], right_index=True, how='outer')
  

Вывод:

    day  pos  value
0    1    1    1.0
1    1   14    2.0
2    1   18    3.0
3    2    1    1.0
4    2   14    2.0
5    3   18    3.0
5    2   18    NaN
5    3    1    NaN
5    3   14    NaN
  

Комментарии:

1. Спасибо. Работает. Я хотел добавить, что первый вариант кажется ограниченным одним столбцом: например, если столбцы [‘day’, ‘hour’, ‘pos’, ‘value’], и каждый день должен иметь все возможные значения ‘hour’, а каждый ‘hour’ должен иметь все возможные значения ‘hour’.значение ‘pos’. Не удалось заставить вариант 1 работать, вариант 2 работает нормально!

Ответ №2:

Вы можете reindex :

 s = pd.MultiIndex.from_product([df["day"].unique(),df["pos"].unique()], names=["day","pos"])

print (df.set_index(["day","pos"]).reindex(s).reset_index())

   day  pos  value
0    1    1    1.0
1    1   14    2.0
2    1   18    3.0
3    2    1    1.0
4    2   14    2.0
5    2   18    NaN
6    3    1    NaN
7    3   14    NaN
8    3   18    3.0
  

Ответ №3:

Я бы избегал руководства product по всем возможным значениям.

Вместо этого можно получить уникальные значения и только reindex за день:

 u = df.pos.unique()

df.groupby('day').apply(lambda s: s.set_index('pos').reindex(u))['value']
  .reset_index()
  

    day  pos  value
0    1    1    1.0
1    1   14    2.0
2    1   18    3.0
3    2    1    1.0
4    2   14    2.0
5    2   18    NaN
6    3    1    NaN
7    3   14    NaN
8    3   18    3.0
  

Ответ №4:

Вы могли бы использовать полную функцию из pyjanitor, чтобы предоставить недостающие значения :

 #  pip install pyjanitor
import pandas as pd
import janitor as jn

df.complete('day', 'pos')
   day  pos  value
0    1    1    1.0
1    1   14    2.0
2    1   18    3.0
3    2    1    1.0
4    2   14    2.0
5    2   18    NaN
6    3    1    NaN
7    3   14    NaN
8    3   18    3.0