Попытка функции получить данные в отдельных диапазонах, подсчитать их и вернуть список результатов. - PullRequest
0 голосов
/ 14 октября 2018

Я пытался написать функцию, которая будет принимать значение из словаря, проверять его диапазон, а затем подсчитывать его в его диапазоне.Возврат списка подсчитанных значений.

Итак, дан следующий словарь:

data={'P1': {'age': 'eighty two', 'salary': '96.0', 'suburb': 'Toorak', 'language': 'English'},
      'P2': {'age': '49', 'salary': '14.0', 'suburb': 'St. Kilda', 'language': 'Chinese'},
      'P3': {'age': '54', 'salary': '75.0', 'suburb': 'Neverland', 'language': 'Italian'}}

И код функции:

def wealth_distribution(data, n_bins, max_salary):
    count = 0
    sal_list = []
    bin_list = []
    bin_width = int(max_salary/n_bins)

    for bins in range(0, max_salary+1, bin_width):
        bin_list.append(bins)

        for val in data.values():
            if val['salary'] == None:
                continue
            for n in bin_list:
                if math.floor(n*bin_width)<=float(val['salary'])<math.floor((n+1)*bin_width):
                    count+= 1
            sal_list.append(count)
    return sal_list

Дано n_bins = 5 иmax_salary = 100, желаемый вывод - [1,0,0,1,1].

Но функция возвращает [0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6].

Ответы [ 4 ]

0 голосов
/ 14 октября 2018
import pandas as pd
from pandas import DataFrame

def wealth_distribution(data, n_bins, max_salary):      

    sal_list = []
    bin_list = []
    bin_width = int(max_salary/n_bins)    
    for bins in range(0, max_salary+1, bin_width):
        bin_list.append(bins)
    sal_list = [0] * (len(bin_list) - 1)         
    df = pd.DataFrame(data)
    for sal in range(0,len(df) - 1):
        salary = float(df.loc['salary'][sal])
        for i in range(len(bin_list) - 1,-1,-1):
            if salary > bin_list[i]:
                sal_list[i] += 1                  
                break   

    return sal_list
0 голосов
/ 14 октября 2018

Во-первых, у вас, похоже, есть ошибка в отступе - for val in data.values(): не должно быть вложено в for bins in range(0, max_salary+1, bin_width): - поэтому вы получаете более длинный список значений.

Во-вторых, ваша логика немного устареларазличными способами - вы сохраняете переменную count, которая устанавливается в ноль только один раз, в начале функции.for n in bin_list: перебирает значения в bin_list, но затем вы умножаете n на bin_width, что не имеет смысла.Вы можете изменить это, используя range(n_bins), чтобы пройти через индексы bin_lists, например:

def wealth_distribution(data, n_bins, max_salary):
    sal_list = [0] * n_bins
    bin_list = []
    bin_width = int(max_salary/n_bins)
    for bins in range(0, max_salary+1, bin_width):
        bin_list.append(bins)
    for val in data.values():
        if val['salary'] == None:
            continue
        for i in range(n_bins):
            if math.floor(i*bin_width)<=float(val['salary'])<math.floor((i+1)*bin_width):
                sal_list[i] += 1
    return sal_list 

Но при ближайшем рассмотрении bin_list на самом деле здесь не имеет смысла.Функция может быть уменьшена до:

def wealth_distribution(data, n_bins, max_salary):
    sal_list = [0] * n_bins
    bin_width = max_salary/n_bins
    for val in data.values():
        if val['salary'] == None:
            continue
        bin_index = int(float(val["salary"]) / bin_width)
        if bin_index < n_bins:
            sal_list[bin_index] += 1
        else:  # salary = max_salary
            sal_list[n_bins-1] += 1
    return sal_list 

Приведенная выше функция рассчитывает индекс бина, а не циклически просматривает бины или индексы.Я также удалил math.floor s, так как они кажутся ненужными и могут привести к некоторым ситуациям, когда небольшая ошибка округления может привести к тому, что некоторые зарплаты не будут классифицированы.

Вы могли бы упростить дальнейшее использование collections.Counter:

from collections import Counter
def wealth_distribution(data, n_bins, max_salary):
    bin_width = max_salary / n_bins
    bins = Counter(min(int(float(val["salary"]) // bin_width), n_bins-1)
               for val in data.values())
    return [bins[i] for i in range(n_bins)]

В numpy есть функция histogram, которая также делает то, что вы хотите, и в качестве бонуса предоставляет массив границ корзины.

import numpy as np
salaries = [float(val["salary"]) for val in data.values()]
sal_list, bin_list = np.histogram(salaries, bins=5, range=(0, 100))

А если вы хотите использовать pandas ... (может быть полезно для других операций с теми же данными)

import pandas as pd
def wealth_distribution(data, n_bins, max_salary):
    df = pd.DataFrame(data).transpose()
    bin_width = max_salary / n_bins
    df["salary_bin"] = (pd.to_numeric(df["salary"]) // bin_width).clip(upper=n_bins-1)
    counts = df["salary_bin"].value_counts()
    return counts.reindex(range(n_bins), fill_value=0).values
0 голосов
/ 14 октября 2018

Я не совсем уверен, что не так с вашим кодом, за исключением того, что он кажется излишне сложным.

Вот как бы я это сделал:

from math import floor

def wealth_distribution(data, n_bins, max_salary):
    sal_list = [0 for _ in range(n_bins)]  # Pre-allocate salary counts.
    bin_width = max_salary // n_bins

    for item in data.values():
        salary = float(item['salary'])

        for i in range(n_bins):
            low = floor(float(i * bin_width))
            high = floor(float(low + bin_width))
            if (salary is not None) and (low <= salary < high):
                sal_list[i] += 1
                break

    return sal_list


data={
    'P1': {'age': 'eighty two', 'salary': '96.0', 'suburb': 'Toorak', 'language': 'English'},
    'P2': {'age': '49', 'salary': '14.0', 'suburb': 'St. Kilda', 'language': 'Chinese'},
    'P3': {'age': '54', 'salary': '75.0', 'suburb': 'Neverland', 'language': 'Italian'}
}


sal_list = wealth_distribution(data, 5, 100)
print(sal_list)  # -> [1, 0, 0, 1, 1]
0 голосов
/ 14 октября 2018

В основном были некоторые проблемы с кодом, который я исправил.Большой проблемой, с которой, я полагаю, вы хотели, была ваша математическая формулировка, которую я также исправил.Это решение не самое эффективное, но работает.

def wealth_distribution(data, n_bins, max_salary):
    count = 0
    bin_list = []
    bin_width = int(max_salary/n_bins)
    for bins in range(0, max_salary+1, bin_width):
        bin_list.append(bins)
    sal_list = [0]*len(bin_list)
    for val in data.values():
        if val['salary']:
            for index, n in enumerate(bin_list):
                if math.floor(n) <= float(val['salary']) < math.floor(n+bin_width):
                    sal_list[index] += 1
    return sal_list
print(wealth_distribution(data, 5, 100))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...