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

#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 для множителя:


а затем вы можете умножить их, как я сделал выше.