Панды перекрестно соединяют фрейм данных и серии

#python #pandas #dataframe #merge

#питон #панды #фрейм данных #слияние

Вопрос:

У меня есть образец фрейма данных

 df = pd.DataFrame({'foo': [1, 2, 3], 'bar': ['A', 'B', 'C']})
 

и серия

 pd.Series([3, 4, 5, 6], name='buzz')
 

Я хочу объединить их, чтобы каждая строка серии реплицировалась для каждой df строки
, так что результирующий фрейм данных эквивалентен этому

 pd.DataFrame({
    'foo': [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3],
    'bar': ['A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C'],
    'buzz': [3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6]
})
 

Я не могу использовать df.merge с внешним соединением, потому что эти два столбца не имеют общих столбцов.

Это довольно легко сделать с помощью обычного python, но мне было интересно, есть ли лучшее решение pandas.

Ответ №1:

Вы можете добавить общий столбец для обоих для перекрестного соединения с Series.to_frame для преобразования Series в один столбец DataFrame :

 df = s.to_frame().assign(a=1).merge(df.assign(a=1), on='a').drop('a', axis=1)
print (df)
    buzz  foo bar
0      3    1   A
1      3    2   B
2      3    3   C
3      4    1   A
4      4    2   B
5      4    3   C
6      5    1   A
7      5    2   B
8      5    3   C
9      6    1   A
10     6    2   B
11     6    3   C
 

Или:

 df = df.assign(a=1).merge(s.to_frame().assign(a=1), on='a').drop('a', axis=1)
print (df)
    foo bar  buzz
0     1   A     3
1     1   A     4
2     1   A     5
3     1   A     6
4     2   B     3
5     2   B     4
6     2   B     5
7     2   B     6
8     3   C     3
9     3   C     4
10    3   C     5
11    3   C     6
 

Другая идея заключается в использовании numpy.tile и numpy.repeat :

 df = (df.loc[np.tile(df.index, len(s))]
        .reset_index(drop=True)
        .assign(buzz = np.repeat(s.to_numpy(), len(df))))
print (df)
    foo bar  buzz
0     1   A     3
1     2   B     3
2     3   C     3
3     1   A     4
4     2   B     4
5     3   C     4
6     1   A     5
7     2   B     5
8     3   C     5
9     1   A     6
10    2   B     6
11    3   C     6
 

РЕДАКТИРОВАТЬ: если все столбцы имеют одинаковые типы (не такие, как здесь), возможно ли использовать решение @Ch3ster, спасибо:

Используя np.tile и np.repeat

 df_arr = np.tile(df.to_numpy(), (len(s), 1))
s_arr = np.repeat(s.to_numpy(), len(df))
df = pd.DataFrame(
    np.column_stack([df_arr, s_arr]), columns=[*df.columns, s.name]
)
 

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

1. @Ch3steR — Проблема вашего решения в том, что все значения являются строками: (

2. Никаких проблем с отменой изменений 😉 Хороший ответ

3. @Ch3steR — он был повторно использован для использования np.tile с индексом и loc

4. @Ch3steR — Спасибо, также открыт заново, потому что частично обманывает.

5. @Ch3steR — Я думаю, лучше включить ваше решение в ответ, спасибо.