Учитывая такой набор данных:
import pandas as pd
rows = [{'key': 'ABC', 'freq': 100}, {'key': 'DEF', 'freq': 60},
{'key': 'GHI', 'freq': 50}, {'key': 'JKL', 'freq': 40},
{'key': 'MNO', 'freq': 13}, {'key': 'PQR', 'freq': 11},
{'key': 'STU', 'freq': 10}, {'key': 'VWX', 'freq': 10},
{'key': 'YZZ', 'freq': 3}, {'key': 'WHYQ', 'freq': 3},
{'key': 'HOWEE', 'freq': 2}, {'key': 'DUH', 'freq': 1},
{'key': 'HAHA', 'freq': 1}]
df = pd.DataFrame(rows)
df['percent'] = df['freq'] / sum(df['freq'])
[вне]:
key freq percent
0 ABC 100 0.328947
1 DEF 60 0.197368
2 GHI 50 0.164474
3 JKL 40 0.131579
4 MNO 13 0.042763
5 PQR 11 0.036184
6 STU 10 0.032895
7 VWX 10 0.032895
8 YZZ 3 0.009868
9 WHYQ 3 0.009868
10 HOWEE 2 0.006579
11 DUH 1 0.003289
12 HAHA 1 0.003289
Цель состоит в том, чтобы
В этом случае подходит ответ:
['ABC', 'DEF']['GHI', 'JKL', 'MNO', 'PQR']['VWX', 'STU', 'YZZ', 'WHYQ', 'HOWEE', 'HAHA', 'DUH']Я пробовал это:
import random
import pandas as pd
rows = [{'key': 'ABC', 'freq': 100}, {'key': 'DEF', 'freq': 60},
{'key': 'GHI', 'freq': 50}, {'key': 'JKL', 'freq': 40},
{'key': 'MNO', 'freq': 13}, {'key': 'PQR', 'freq': 11},
{'key': 'STU', 'freq': 10}, {'key': 'VWX', 'freq': 10},
{'key': 'YZZ', 'freq': 3}, {'key': 'WHYQ', 'freq': 3},
{'key': 'HOWEE', 'freq': 2}, {'key': 'DUH', 'freq': 1},
{'key': 'HAHA', 'freq': 1}]
df = pd.DataFrame(rows)
df['percent'] = df['freq'] / sum(df['freq'])
bin_50_100 = []
bin_10_50 = []
bin_10 = []
total_percent = 1.0
for idx, row in df.sort_values(by=['freq', 'key'], ascending=False).iterrows():
if total_percent > 0.5:
bin_50_100.append(row['key'])
elif 0.1 < total_percent < 0.5:
bin_10_50.append(row['key'])
else:
bin_10.append(row['key'])
total_percent -= row['percent']
print(random.sample(bin_50_100, 1))
print(random.sample(bin_10_50, 2))
print(random.sample(bin_10, 4))
[вне]:
['DEF']
['MNO', 'PQR']
['HOWEE', 'WHYQ', 'HAHA', 'DUH']
Но есть ли более простой способ решить проблему?






Давай попробуем:
bins = [0, 0.1, 0.5, 1]
samples = [3,3,1]
df['sample'] = pd.cut(df.percent[::-1].cumsum(), # accumulate percentage
bins=[0, 0.1, 0.5, 1], # bins
labels=False # num samples
).astype(int)
df.groupby('sample').apply(lambda x: x.sample(n=samples[x['sample'].iloc[0])] )
Выход:
key freq percent sample
sample
1 0 ABC 100 0.328947 1
2 2 GHI 50 0.164474 2
5 PQR 11 0.036184 2
4 7 VWX 10 0.032895 4
6 STU 10 0.032895 4
12 HAHA 1 0.003289 4
10 HOWEE 2 0.006579 4
Спасибо за обновление!! Почему это samples = np.array([3,3,1])?
Это для предварительной индексации массива numpy. Передача label=False в cuts возвращает номера бинов. например [0, 1, 2, 0, 1, 1]. Затем мы используем индексацию numpy для нарезки соответствующего количества выборок.
Я получаю другой результат от вашего.
С [3, 3, 1] я получаю только 2 выборки бинов, а не 3 =(
@alvas ах, да, глупый я. Обновил ответ. Нам не нужно делать np.array для samples.
Я думаю, что в последнем grouby есть какая-то синтаксическая ошибка, но я думаю, что понял идею =) Спасибо!!
df.groupby('sample').apply(lambda x: x.sample(n=samples[x['sample'].iloc[0]])) =)
Посмотрите, поможет ли это.
df = pd.DataFrame(rows)
df['percent'] = df['freq'] / sum(df['freq'])
s = list(1 - df['percent'].cumsum())
s.pop(-1)
s.insert(0,1.0)
df['cum_lag'] = s
print(df[df['cum_lag'] > 0.5]['key'])
Ну это при условии, что нет. образцов уникальны. т.е.
1 2 4, но в противном случае выдаст ошибкуCategorical categories must be unique.