Средние значения словарей

avatar
freshman_2021
8 августа 2021 в 21:45
133
2
3

Использование набора данных радужной оболочки от sklearn. Я разделяю данные, применяя Perceptron, записывая оценки в словарь, который сопоставляет размер выборки (ключ), используемый для подбора модели, к соответствующей оценке (обучающие и тестовые оценки в виде кортежа)

Это дает 3 словаря, так как я запускаю цикл 3 раза. Как найти среднее значение результатов за 3 итерации? Я пробовал хранить словари в списке и в среднем, но это не сработало

например: если словарь

{21: (0.85, 0.82), 52: (0.80, 0.62), 73: (0.82, 0.45), 94: (0.81, 0.78)}
{21: (0.95, 0.91), 52: (0.80, 0.89), 73: (0.84, 0.87), 94: (0.79, 0.41)}
{21: (0.809, 0.83), 52: (0.841, 0.77), 73: (0.84, 0.44), 94: (0.79, 0.33)}

Вывод должен быть {21:(0.869,0.853),52.....}, где первый элемент значения для ключа 21 равен 0,85+0,95+0,809/3, а второй равен 0,82+0,91+0,83/3

import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.linear_model import Perceptron
from sklearn.model_selection import train_test_split

score_list=shape_list=[]
iris = load_iris()
props=[0.2,0.5,0.7,0.9]
df = pd.DataFrame(data= np.c_[iris['data'], iris['target']], columns= iris['feature_names'] + ['target'])
y=df[list(df.loc[:,df.columns.values =='target'])]
X=df[list(df.loc[:,df.columns.values !='target'])]

# number of trials
for i in range(3):
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, train_size=0.7)
    results = {}
    for i in props:
        size = int(i*len(X_train))
        ix = np.random.choice(X_train.index, size=size, replace = False)
        sampleX = X_train.loc[ix]
        sampleY = y_train.loc[ix]
        #apply model
        modelP = Perceptron(tol=1e-3)
        modelP.fit(sampleX, sampleY)
        train_score = modelP.score(sampleX,sampleY)
        test_score = modelP.score(X_test,y_test)
        #store in dictionary
        results[size] = (train_score, test_score)

    print(results)

Кроме того, если кто-то разбирается в статистике, есть ли способ найти стандартную ошибку для испытаний и распечатать среднюю стандартную ошибку для каждого размера выборки (ключ словаря)?

Источник

Ответы (2)

avatar
Trenton McKinney
9 августа 2021 в 22:06
2
  • Обновите существующий цикл, чтобы сохранить results в list, rl
  • Загрузите rl в фрейм данных, так как вы уже используете pandas
  • Развернуть столбцы tuples на отдельные столбцы
  • Используйте .agg, чтобы получить показатели
  • Тест с python 3.8 и pandas 1.3.1
    • f-strings (например, f'TrS{c}', f'TeS{c}') требуется python >= 3.6

Обновления существующего кода

# select columns for X and y
y = df.loc[:, 'target']
X = df.loc[:, iris['feature_names']]

# number of trials
rl = list()  # add: save results to a list
for i in range(3):
    ...
    results = {}
    for i in props:
        ...
        ...
    rl.append(results)  # add: append results

Новый код для получения показателей

  • Преобразование metrics в list из tuples проще, чем tuple из tuples, потому что tuple неизменяем после создания. Это означает, что tuples можно добавить к существующему list, но не к существующему tuple.
    • Therefore, it's easier to use defaultdict to create a list of tuples, and then convert each value to a tuple with map.
    • k[3:] требует, чтобы числа всегда начинались с index 3
from collections import defaultdict

# convert rl to a dataframe
rl = [{21: (0.5714285714285714, 0.6888888888888889), 52: (0.6153846153846154, 0.7111111111111111), 73: (0.7123287671232876, 0.6222222222222222), 94: (0.7127659574468085, 0.6)}, {21: (0.6190476190476191, 0.6444444444444445), 52: (0.6923076923076923, 0.6444444444444445), 73: (0.3698630136986301, 0.35555555555555557), 94: (0.7978723404255319, 0.7777777777777778)}, {21: (0.8095238095238095, 0.5555555555555556), 52: (0.7307692307692307, 0.5555555555555556), 73: (0.7534246575342466, 0.5777777777777777), 94: (0.6170212765957447, 0.7555555555555555)}]
df = pd.DataFrame(rl)

# display(df)
                                         21                                        52                                         73                                        94
0  (0.5714285714285714, 0.6888888888888889)  (0.6153846153846154, 0.7111111111111111)   (0.7123287671232876, 0.6222222222222222)                 (0.7127659574468085, 0.6)
1  (0.6190476190476191, 0.6444444444444445)  (0.6923076923076923, 0.6444444444444445)  (0.3698630136986301, 0.35555555555555557)  (0.7978723404255319, 0.7777777777777778)
2  (0.8095238095238095, 0.5555555555555556)  (0.7307692307692307, 0.5555555555555556)   (0.7534246575342466, 0.5777777777777777)  (0.6170212765957447, 0.7555555555555555)

# expand the tuples
for c in df.columns:
    df[[f'TrS{c}', f'TeS{c}']] = pd.DataFrame(df[c].tolist(), index= df.index)
    df.drop(c, axis=1, inplace=True)

# get the mean and std
metrics = df.agg(['mean', 'std']).round(3)

# display(metrics)
      TrS21  TeS21  TrS52  TeS52  TrS73  TeS73  TrS94  TeS94
mean  0.667  0.630  0.679  0.637  0.612  0.519  0.709  0.711
std   0.126  0.068  0.059  0.078  0.211  0.143  0.090  0.097

# convert to dict
dd = defaultdict(list)

for k, v in metrics.to_dict().items(): 
    dd[int(k[3:])].append(tuple(v.values()))
    
dd = dict(zip(dd, map(tuple, dd.values())))
print(dd)

[out]:
{21: ((0.667, 0.126), (0.63, 0.068)),
 52: ((0.679, 0.059), (0.637, 0.078)),
 73: ((0.612, 0.211), (0.519, 0.143)),
 94: ((0.709, 0.09), (0.711, 0.097))}
freshman_2021
10 августа 2021 в 02:24
0

Мой блокнот Jupyter возвращает ошибку в строке 11

freshman_2021
10 августа 2021 в 02:24
0

df[[f'TrS{c}', f'TeS{c}']] = pd.DataFrame(df[c].tolist(), index= df.index) ^ SyntaxError: недопустимый синтаксис

Trenton McKinney
10 августа 2021 в 02:25
0

@freshman_2021 какая версия питона и какая версия панд?

freshman_2021
10 августа 2021 в 02:28
0

Панды: 0.23.4 Python: 3.5.2

Trenton McKinney
10 августа 2021 в 02:28
1

@tdy Я думаю, что это f-строки, для них требуется python >= 3.6

Trenton McKinney
10 августа 2021 в 02:33
1

@freshman_2021freshman_2021 Я добавил версии, в которых тестировался. Срок службы Python 3.5 истек, а текущая версия pandas — 1.3.1. Вы можете использовать df[['TrS{}'.format(c), 'TeS{}'.format(c)]] = pd.DataFrame(df[c].tolist(), index= df.index), но вам следует подумать о новом инструменте.

freshman_2021
10 августа 2021 в 02:36
1

На самом деле я нахожусь в процессе приобретения нового ноутбука и в настоящее время работаю над арендованным устройством... Я отвлекаюсь.. Это работает как шарм... Большое спасибо.

Trenton McKinney
10 августа 2021 в 02:38
0

@freshman_2021 Когда вы устанавливаете Python на свой новый компьютер, самым простым способом будет дистрибутив Anaconda.

avatar
VirtualScooter
8 августа 2021 в 22:23
1

Предполагая, что все результаты сохранены в списке rl, следующая программа будет сделать расчет:

rl = [
    {21: (0.85, 0.82), 52: (0.80, 0.62), 73: (0.82, 0.45), 94: (0.81, 0.78)},
    {21: (0.95, 0.91), 52: (0.80, 0.89), 73: (0.84, 0.87), 94: (0.79, 0.41)},
    {21: (0.809, 0.83), 52: (0.841, 0.77), 73: (0.84, 0.44), 94: (0.79, 0.33)}
]

vd = {}
for k in rl[0].keys():
    vals = [[], []]
    for i in range(len(rl)):
        vals[0].append(rl[i][k][0])
        vals[1].append(rl[i][k][1])
    vd[k] = sum(vals[0])/len(vals[0]), sum(vals[1])/len(vals[1])
print(vd)

Вывод:

# {21: (0.8696666666666667, 0.8533333333333334),
#  52: (0.8136666666666666, 0.7600000000000001),
#  73: (0.8333333333333334, 0.5866666666666667),
#  94: (0.7966666666666667, 0.5066666666666667)}

Или, если используются zip и numpy в одном списке rl. Здесь мы можем также удобно рассчитать стандартную ошибку таким же образом как среднее:

import numpy as np

rl2 = list(zip(rl[0].keys(), rl[0].values(), rl[1].values(), rl[2].values()))
vd2 = {rl2[i][0] : np.mean(list(zip(*rl2[i][1:])), axis=1) for i in range(len(rl2))}
print(vd2)
vd2_std = {rl2[i][0] : np.std(list(zip(*rl2[i][1:])), axis=1) for i in range(len(rl2))}
print(vd2)
print("Standard error\n", vd2_std)

Вывод:

# {21: array([0.86966667, 0.85333333]),
#  52: array([0.81366667, 0.76      ]),
#  73: array([0.83333333, 0.58666667]),
#  94: array([0.79666667, 0.50666667])}
# Standard error
# {21: array([0.05921899, 0.04027682]),
#  52: array([0.01932759, 0.11045361]),
#  73: array([0.00942809, 0.20038851]),
#  94: array([0.00942809, 0.19601587])}