python и pandas: используйте количество ячеек из одного df, чтобы получить аналогичное количество ячеек из другого df без общих столбцов

#python #pandas #dataframe

Вопрос:

Учитывая df1, я знаю, как получить значения в ячейках с помощью .value_counts() :

 df1 = pd.DataFrame({'numbers': [0.1, 0.11, 0.2, 0.3, 0.33, 0.6, 0.66, 0.7, 0.9, 1],
'another_column': ['blue', 'blue', 'blue', 'red', 'green', 'purple', 'blue', 'blue', 'blue', 'orange']})

df1['numbers'].value_counts(bins=[0, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1])
 

Результат:

 (0.6, 0.7]       2
(0.1, 0.2]       2
(0.9, 1.0]       1
(0.8, 0.9]       1
(0.5, 0.6]       1
(0.3, 0.4]       1
(0.2, 0.3]       1
(-0.001, 0.1]    1
(0.7, 0.8]       0
(0.4, 0.5]       0
Name: numbers, dtype: int64
 

Учитывая, что другой df намного больше, чем df1 (пример ниже):

 df2 = pd.DataFrame({'numbers': [0.1, 0.11, 0.2, 0.3, 0.33, 0.6, 0.66, 0.7, 0.9, 0.1, 0.11, 0.2, 0.3, 0.33, 0.6, 0.66, 0.7, 0.9, 0.1, 0.11, 0.2, 0.3, 0.33, 0.6, 0.66, 0.7, 0.98],
'nonshared_column': ['cat', 'dog', 'cat', 'dog', 'fish', 'cat', 'dog', 'dog', 'fish', 'cat', 'dog', 'cat', 'dog', 'fish', 'cat', 'dog', 'dog', 'fish', 'cat', 'dog', 'cat', 'dog', 'fish', 'cat', 'dog', 'dog', 'fish']})
 

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

таким образом, выходной df будет иметь 1 строку со значениями «чисел» между 0-0, 1, 2 строками со значениями «чисел» между 0,1-0,2 … вплоть до 1 строки со значениями «чисел» в диапазоне от 0,9 до 1. Выходные строки df должны включать все столбцы из df2 ( nonshared_column в этом примере, а также numbers столбец).

Ответ №1:

Использовать cut bins с индексом от по Series имени s :

 s = df1['numbers'].value_counts(bins=[0, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1])

df2['new'] = pd.cut(df2['numbers'], bins=s.index)
print (df2)
    numbers nonshared_column            new
0      0.10              cat  (-0.001, 0.1]
1      0.11              dog     (0.1, 0.2]
2      0.20              cat     (0.1, 0.2]
3      0.30              dog     (0.2, 0.3]
4      0.33             fish     (0.3, 0.4]
5      0.60              cat     (0.5, 0.6]
6      0.66              dog     (0.6, 0.7]
7      0.70              dog     (0.6, 0.7]
8      0.90             fish     (0.8, 0.9]
9      0.10              cat  (-0.001, 0.1]
10     0.11              dog     (0.1, 0.2]
11     0.20              cat     (0.1, 0.2]
12     0.30              dog     (0.2, 0.3]
13     0.33             fish     (0.3, 0.4]
14     0.60              cat     (0.5, 0.6]
15     0.66              dog     (0.6, 0.7]
16     0.70              dog     (0.6, 0.7]
17     0.90             fish     (0.8, 0.9]
18     0.10              cat  (-0.001, 0.1]
19     0.11              dog     (0.1, 0.2]
20     0.20              cat     (0.1, 0.2]
21     0.30              dog     (0.2, 0.3]
22     0.33             fish     (0.3, 0.4]
23     0.60              cat     (0.5, 0.6]
24     0.66              dog     (0.6, 0.7]
25     0.70              dog     (0.6, 0.7]
26     0.98             fish     (0.9, 1.0]
 

Последнее, если нужно, количество по всем 3 столбцам:

 df3 = df2.groupby(['numbers','nonshared_column','new'], observed=True).size().reset_index(name='count')
print (df3)
   numbers nonshared_column            new  count
0     0.10              cat  (-0.001, 0.1]      3
1     0.11              dog     (0.1, 0.2]      3
2     0.20              cat     (0.1, 0.2]      3
3     0.30              dog     (0.2, 0.3]      3
4     0.33             fish     (0.3, 0.4]      3
5     0.60              cat     (0.5, 0.6]      3
6     0.66              dog     (0.6, 0.7]      3
7     0.70              dog     (0.6, 0.7]      3
8     0.90             fish     (0.8, 0.9]      2
9     0.98             fish     (0.9, 1.0]      1
 

Редактировать:

Если нужно то же самое, например s , сначала используйте sample для случайного порядка строк, а затем head() с помощью map by s для фильтрации по количеству:

 df2 = df2.sample(frac=1).groupby('new', group_keys=False).apply(lambda x: x.head(s[x.name])).sort_index()
print (df2)
    numbers nonshared_column            new
2      0.20              cat     (0.1, 0.2]
3      0.30              dog     (0.2, 0.3]
4      0.33             fish     (0.3, 0.4]
9      0.10              cat  (-0.001, 0.1]
11     0.20              cat     (0.1, 0.2]
14     0.60              cat     (0.5, 0.6]
15     0.66              dog     (0.6, 0.7]
17     0.90             fish     (0.8, 0.9]
24     0.66              dog     (0.6, 0.7]
26     0.98             fish     (0.9, 1.0]
 

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

1. Это отлично подходит для первой части! Как насчет случайного выбора строк из df2, чтобы у него было то же количество ячеек, что и у df1?