#python #string #dataframe #function #logic
Вопрос:
Я пытаюсь написать функцию, которая принимает строковый ответ в столбце «Частота» и вычисляет общее количество дней в году, когда кто-то употреблял алкоголь.
Три основных значения, которые я пытаюсь извлечь из строки, — это числа, которые существуют в инструкции, и слово (неделя, месяц, год), чтобы рассчитать среднее общее количество дней, когда кто-то пил в течение года. Например, если бы кто-то пил 2-3 раза в месяц, уравнение было бы (2 3/2)*12 = 30 раз в год. В таблице данных ниже показан образец данных.
Частота |
---|
1 день в месяц |
3 дня в неделю |
от 1 до 2 дней в год |
2 дня в неделю |
1 день в месяц |
6-11 дней в году |
5-6 дней в неделю |
В таблице, которую я пытаюсь создать, будут указаны средние дни в году, как показано ниже:
Частота в год |
---|
12 |
156 |
1.5 |
104 |
12 |
8.5 |
286 |
До сих пор я писал код ниже:
import pandas as pd
AlcData = pd.read_excel('Alcohol_Data.xlsx')
#add new column with unittime value for use in function
AlcData['unittime'] = AlcData.Frequency.str.extract(r'b(w )
В настоящее время я получаю ошибку: "Объект" Серия "не имеет атрибута "разделение "" при попытке извлечь числа из строк в списки. Кто-нибудь знает, как исправить эту ошибку в функции? Что еще более важно, является ли этот подход (использование длины списка для назначения этих переменных и вычисления чисел) лучшим способом решения этой проблемы?
Я долго боролся с этим, поэтому любые советы о том, как вычислить эту информацию, были бы чрезвычайно полезны.
Комментарии:
1. Почему у вас есть цикл для "диапазона(1, 11)"?
2. @MichaelButscher, потому что наибольшее число в любом из строковых ответов равно 11, а наименьшее-1. Хотя я не уверен, что это правильно
Ответ №1:
Это в значительной степени переписано, но вот как это можно сделать, просто pandas
:
In [92]: (
...: df['Frequency']
...: .str.split()
...: .str[-1].map({'week': 52, 'month': 12, 'year': 1})
...: .mul(
...: df['Frequency']
...: .str.extract(r'(d )D*(d )?')
...: .ffill(axis=1)
...: .astype(int).mean(axis=1)
...: )
...: )
Out[92]:
0 12.0
1 156.0
2 1.5
3 104.0
4 12.0
5 8.5
6 286.0
dtype: float64
Мы можем разбить его на вычисление числовых частей, а затем на множитель. Вы можете вывести числа с помощью регулярного выражения, аналогичного тому, что вы делали раньше:
In [89]: df['Frequency'].str.extract(r'(d )D*(d )?')
Out[89]:
0 1
0 1 NaN
1 3 NaN
2 1 2
3 2 NaN
4 1 NaN
5 6 11
6 5 6
и оттуда вы можете использовать .ffill()
и .mean()
превратить его в одно число:
In [90]: df['Frequency'].str.extract(r'(d )D*(d )?').ffill(axis=1).astype(int).mean(axis=1)
Out[90]:
0 1.0
1 3.0
2 1.5
3 2.0
4 1.0
5 8.5
6 5.5
dtype: float64
Если вы знаете, что это всегда заканчивается year
, month
, или week
, вы можете просто снять это и использовать map
для множителя:
In [91]: df['Frequency'].str.split().str[-1].map({'week': 52, 'month': 12, 'year': 1})
Out[91]:
0 12
1 52
2 1
3 52
4 12
5 1
6 52
Name: Frequency, dtype: int64
а затем вы можете умножить их, как я сделал выше.
,
expand = True)
def calculatetotaldays(row):
for x in range(1,11):
#read in row item as string value
string = AlcData.Frequency
# create list of number values from the string
numbers = [int(i) for i in string.split() if i.isdigit()]
#compute total days if list has length of 1
if len(numbers) == 1:
x = [numbers[j] for j in (0)]
if row[AlcData.unittime] == 'week':
total = x*52
elif row[AlcData.unittime] == 'month':
total = x*12
elif row[AlcData.unittime] == 'year':
total = x
#compute total days if list has length of 2
if len(numbers) == 2:
x, y = [numbers[j] for j in (0, 1)]
if row[AlcData.unittime] == 'week':
total = (((x y)/2)*52)
elif row[AlcData.unittime] == 'month':
total = (((x y)/2)*12)
elif row[AlcData.unittime] == 'year':
total = ((x y)/2)
return total
AlcData['totalperyear'] = AlcData.apply(calculatetotaldays, axis=1)
В настоящее время я получаю ошибку: «Объект» Серия «не имеет атрибута «разделение «» при попытке извлечь числа из строк в списки. Кто-нибудь знает, как исправить эту ошибку в функции? Что еще более важно, является ли этот подход (использование длины списка для назначения этих переменных и вычисления чисел) лучшим способом решения этой проблемы?
Я долго боролся с этим, поэтому любые советы о том, как вычислить эту информацию, были бы чрезвычайно полезны.
Комментарии:
1. Почему у вас есть цикл для «диапазона(1, 11)»?
2. @MichaelButscher, потому что наибольшее число в любом из строковых ответов равно 11, а наименьшее-1. Хотя я не уверен, что это правильно
Ответ №1:
Это в значительной степени переписано, но вот как это можно сделать, просто pandas
:
Мы можем разбить его на вычисление числовых частей, а затем на множитель. Вы можете вывести числа с помощью регулярного выражения, аналогичного тому, что вы делали раньше:
и оттуда вы можете использовать .ffill()
и .mean()
превратить его в одно число:
Если вы знаете, что это всегда заканчивается year
, month
, или week
, вы можете просто снять это и использовать map
для множителя:
а затем вы можете умножить их, как я сделал выше.