#python #excel #data-analysis #aggregation #countif
Вопрос:
Давний пользователь Excel превратился здесь в нового пользователя Python. У меня есть следующий фрейм данных идентификаторов продуктов:
productID sales
6976849 194,518,557
11197085 277,387,647
70689391 197,511,925
70827164 242,995,691
70942756 1,529,319,200
(В интерфейсе это выглядит не очень красиво, но в Python мне удалось поместить это в фрейм данных со столбцом для идентификатора и столбцом для продаж.)
Каждый идентификатор продукта содержит общее количество продаж.
Что мне нужно, так это подсчитать, сколько продуктов имеют более 200 000 000 продаж, а также сколько продуктов имеют менее 200 000 000 продаж.
Общее количество ведер Более 200 000 000 x Менее 200 000 000 лет
В Excel я бы сделал это с помощью функции быстрого подсчета, но я не уверен, как это работает в Python.
Мне на удивление трудно найти, как это сделать-может ли кто-нибудь указать мне правильное направление? Даже просто названия функций, чтобы я мог прочитать о них, были бы полезны!
Спасибо!!
Комментарии:
1. Воспользуйся
Pandas
2. Как новичок, я бы лично не рекомендовал использовать фреймы данных pandas, пока вы не познакомитесь с самим языком. Они довольно мощные, но ваше приложение довольно простое и не нуждается в их гибкости. Сохранение файла в формате csv, затем чтение файла и анализ текста будут хорошим упражнением в обучении работе с файлами, преобразованию строк и обработке простых структур данных (например, списков и т. Д.).
3. Ты прав, @Аарон. Можете ли вы ответить на вопрос с помощью
csv
модуля, пожалуйста?
Ответ №1:
Использовать Pandas
и value_counts
:
import pandas as pd
df = pd.read_excel('data.xlsx')
over, under = df['sales'].gt(200000000).value_counts().tolist()
Выход:
>>> over
3
>>> under
2
Шаг за шагом:
# Display your data after load file
>>> df
productID sales
0 6976849 194518557
1 11197085 277387647
2 70689391 197511925
3 70827164 242995691
4 70942756 1529319200
# Select the column 'sales'
>>> df['sales']
0 194518557
1 277387647
2 197511925
3 242995691
4 1529319200
Name: sales, dtype: int64
# Sales are greater than 200000000? (IF part of COUNTIF)
>>> df['sales'].gt(200000000)
0 False
1 True
2 False
3 True
4 True
Name: sales, dtype: bool
# Count True (over) and False (under) (COUNT part of COUNTIF)
>>> df['sales'].gt(200000000).value_counts()
True 3
False 2
Name: sales, dtype: int64
# Convert to list
>>> df['sales'].gt(200000000).value_counts().tolist()
[3, 2]
# Set variables over / under
>>> over, under = df['sales'].gt(200000000).value_counts().tolist()
Обновить
Я должен также добавить, что в наборе данных 100 миллионов строк, и мне понадобится больше сегментов, что-то вроде Более 500 миллионов между 200 миллионами и 500 миллионами между 100 миллионами и 200 миллионами менее 100 миллионов. Можете ли вы сказать мне, как я буду устанавливать сегменты?
Использовать pd.cut
и value_counts
:
df['buckets'] = pd.cut(df['sales'], right=False, ordered=True,
bins=[0, 100e6, 200e6, 500e6, np.inf],
labels=['under 100M', '100-200M',
'200-500M', 'over 500M'])
>>> df
productID sales buckets
0 6976849 194518557 100-200M
1 11197085 277387647 200-500M
2 70689391 197511925 100-200M
3 70827164 242995691 200-500M
4 70942756 1529319200 over 500M
>>> df.value_counts('buckets', sort=False)
buckets
under 100M 0
100-200M 2
200-500M 2
over 500M 1
dtype: int64
Комментарии:
1. Спасибо! Я также должен добавить, что в наборе данных 100 миллионов строк, и мне понадобится больше блоков, что-то около 500 миллионов между 200 миллионами и 500 миллионами между 100 миллионами и 200 миллионами менее 100 миллионов. Можете ли вы сказать мне, как я буду устанавливать блоки?
2. Я обновил свой ответ в соответствии с вашим комментарием. Не забудьте принять ответ , если он соответствует вашим потребностям. Это важно для всех нас.
Ответ №2:
Существует множество очень мощных библиотек, которые помогут вам быстро выполнять задачи, но вы упомянули, что только начинаете, поэтому я бы рекомендовал придерживаться только самого python в качестве учебного опыта.
Excel может сохранять файлы в формате «CSV», который представляет собой очень простой текстовый формат файла. CSV-файлы, как правило, представляют собой просто построчное представление каждой строки в вашей электронной таблице, со столбцами, разделенными запятыми. Очень простым решением вашего вопроса может быть чтение такого файла строка за строкой, определение того, больше или меньше количество продаж, чем заданное число, и добавление одного в соответствующую группу.
Начать с чтения файла довольно просто. Чтение файлов в коде немного отличается от того, к чему вы привыкли, но это очень просто и почти всегда одинаково для разных языков программирования. Сначала вы» открываете » файл, который в основном запрашивает доступ операционной системы. ОС определит, должен ли у вас быть доступ или нет, и если да, предоставит вам доступ к тому, что составляет курсор, который может сканировать файл. Этот «курсор» часто называют «дескриптором файла» или в python просто «файловым объектом».
file_obj = open("data.csv", "r") #"r" for reading mode (instead of write)
Как только у нас будет дескриптор, мы сможем вызвать его read
метод для чтения части или всего файла. Передача числа покажет, сколько символов (новая строка и некоторые другие невидимые коды считаются символом) для чтения, или в python вы не можете передавать параметры, и он прочитает весь файл. Поскольку мы открыли файл в текстовом режиме (по умолчанию), мы получим обычную строку.
file_contents = file_obj.read()
Теперь, когда мы скопировали содержимое файла в строку, мы можем закрыть файл и сообщить операционной системе, что мы закончили с ним.
file_obj.close()
Вы часто можете видеть это немного по-другому в python, используя with
контекст, чтобы немного очистить код и убедиться, что файл всегда закрывается:
with open("data.csv", "r") as file_obj:
file_contents = file_obj.read()
Теперь у вас есть большая длинная строка, содержащая весь CSV-файл. Мы хотим иметь возможность переходить строка за строкой, поэтому нам приходится разделять строку на части в любом месте, где мы находим символ новой строки. Строки Python имеют удобный способ сделать это с помощью str.split
метода:
file_lines = file_contents.split("n") #split the string into a list of strings by splitting on n chars
Теперь с помощью этого списка мы создадим цикл для чтения каждой строки и определим, было ли у продукта более или менее 200 000 000 продаж. Для этого нам нужно будет найти соответствующий раздел каждой строки, преобразовать его в число и с помощью if
оператора решить, что с ним делать. Простейшая форма цикла python состоит в том, чтобы просмотреть каждый элемент в простом списке элементов: for line in file_lines:
. Теперь на каждой итерации внутри цикла, line
переменная будет заполнена тем, что было в этой строке файла. Пока в csv — файле нет пустых строк и заголовков, нам в значительной степени нужно только найти второе значение (разделенное запятой) и преобразовать его в число. Здесь мы снова воспользуемся этим str.split
методом, чтобы разделить строку на запятую и преобразовать второй элемент в целое число (помните, что python использует индексацию на основе 0, поэтому 2-й элемент будет иметь индекс 1). Отсюда мы можем добавить некоторую логику, чтобы определить, следует ли нам считать один меньше или больше 200 миллионов.
over = 0
under = 0
for line in file_lines:
line_items = line.split(",")
sales = int(line_items[1])
if sales > 200000000:
over = over 1
else:
under = under 1
Наконец, вот более продвинутая версия после прочтения вашего комментария о необходимости большего количества «ведер».
buckets = [0] * 8 #list of 8 buckets each starting at 0
bucket_edges = [0, 1e6, 2e6, 5e6, 1e7, 2e7, 5e7, 1e8, 2e8] #an even more advanced version would find the max and min of the sales figures, and dynamically calculate the bucket edges
with open("data.csv") as f: #"r" mode is actually the default
sales = [] #an empty list
for line in f: #a default behavior of file handles is to read line-by-line in for loops
line = line.strip() #remove leading and trailing whitespace
if not line: #an empty string will act like "False"
continue #advance to the next loop iteration
sales.append(int(line.split(",")[1])) #combine a few operations in a single line, and build up a list of sales figures
for sale in sales:
for i in range(len(buckets)):
if bucket_edges[i] <= sale < bucket_edges[i 1]:
buckets[i] = 1
for i in range(len(buckets)):
print(bucket_edges[i], "to", bucket_edges[i 1], ":", buckets[i])
Комментарии:
1. Хорошее объяснение, за это 1. Но вы должны использовать
csv
модуль (это модуль стандартной библиотеки). Вероятно, вы также можете использоватьbisect
модули (bisect_left) иcollections
(defaultdict). Если вы не используете какие-либо модули из стандартной библиотеки, Python будет не так полезен.
Ответ №3:
Если вы используете convtools
файл xlsx и его преобразование в csv, то короткий ответ таков:
# pip install convtools
from convtools import conversion as c
converter = c.aggregate({
"below_200": c.ReduceFuncs.Count(where=c.item("sales") < 200000000),
"above_200": c.ReduceFuncs.Count(where=c.item("sales") >= 200000000),
}).gen_converter()
results = converter(list_of_dicts)
Более длинный:
import csv
# pip install convtools
from convtools import conversion as c
buckets = [
(None, 200000000),
(200000000, 220000000),
(220000000, 240000000),
(220000000, None),
]
def bucket_to_condition(bucket, input_):
conditions = []
left, right = bucket
if left is not None:
conditions.append(input_ >= left)
if right is not None:
conditions.append(input_ < right)
if not conditions:
return {}
return {
"where": c.and_(*conditions) if len(conditions) > 1 else conditions[0]
}
with open("input_data.csv", "w") as f:
reader = csv.reader(f)
# skip header (assuming it's known)
next(header)
converter = (
c.iter(
{
"productID": c.item(0),
"sales": c.item(1).as_type(int),
}
)
.pipe(
c.aggregate(
{
f"{bucket}": c.ReduceFuncs.Count(
**bucket_to_condition(bucket, c.item("sales")),
)
for bucket in buckets
}
)
)
.gen_converter()
)
results = converter(reader)