Пример, рассмотрим
дф:
Time colA colB
0 1.1 2 2
1 2.2 2 2
2 3.4 3 5
3 4.5 3 5
4 5.6 4 5
5 6.2 4 6
6 7.4 4 6
7 8.5 2 6
8 9.8 2 5
9 10.1 2 5
10 11.2 2 5
Ожидаемый результат — это CSV-файл отчета со следующими столбцами:
Col_name unique_value Duration
colA 2 3.8s
colA 3 1.1s
colA 4 1.8s
colB 2 1.1s
colB 5 3.6s
colB 6 2.3s
(например): Чтобы вычислить colA :
unique value = 2
Duration = [1st consecutive appearance of 2 time difference (2.2-1.1)] + [2nd consecutive appearance time difference (11.2-8.5)] = 1.1 + 2.7 = 3.8s
Одна из логик, которые я пробовал:
df["answer"] = df['colA'].diff().eq(0)
В качестве следующего шага я планировал собрать все False в одном списке и True в одном списке и получить разницу в списке.
Меня смущает то, как связать их с уникальными ценностями.
Помогите мне выяснить, работает ли существующая логика или ее следует изменить.
*Хорошим началом будет создание нового столбца с указанием последовательных значений True и False. Однако, чтобы вычислить продолжительность для каждого уникального значения в каждом столбце, вы можете использовать следующие шаги: Переберите каждое уникальное значение в каждом столбце. Для каждого уникального значения найдите последовательные вхождения и рассчитайте продолжительность. Сохраните результаты в новом фрейме данных.
import pandas as pd
# Sample DataFrame
data = {
'Time': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
'colA': [1.1, 2.2, 3.4, 4.5, 5.6, 6.2, 7.4, 8.5, 9.8, 10.1, 11.2],
'colB': [2, 2, 3, 3, 4, 4, 4, 2, 2, 2, 2]
}
df = pd.DataFrame(data)
# Function to calculate duration for each unique value in a column
def calculate_duration(column_name):
durations = []
unique_values = df[column_name].unique()
for value in unique_values:
# Find consecutive occurrences of the value
consecutive_indices = df[df[column_name] == value].index.to_list()
consecutive_occurrences = []
current_occurrence = [consecutive_indices[0]]
for i in range(1, len(consecutive_indices)):
if consecutive_indices[i] - consecutive_indices[i-1] == 1:
current_occurrence.append(consecutive_indices[i])
else:
consecutive_occurrences.append(current_occurrence)
current_occurrence = [consecutive_indices[i]]
consecutive_occurrences.append(current_occurrence)
# Calculate duration for each consecutive occurrence
for occurrence in consecutive_occurrences:
start_time = df.iloc[occurrence[0]]['Time']
end_time = df.iloc[occurrence[-1]]['Time']
duration = end_time - start_time
durations.append((value, duration))
return durations
# Create a DataFrame to store results
report_df = pd.DataFrame(columns=['Col_name', 'unique_value', 'Duration'])
# Calculate durations for each column
for column in df.columns[1:]:
durations = calculate_duration(column)
for value, duration in durations:
report_df = report_df.append({'Col_name': column, 'unique_value': value, 'Duration': duration}, ignore_index=True)
# Export to CSV
report_df.to_csv('report.csv', index=False)
Экспортируйте фрейм данных в файл CSV.*
Для справки, это df, который я использовал: # Пример данных DataFrame = { 'Time': [1.1, 2.2, 3.4, 4.5, 5.6, 6.2, 7.4, 8.5, 9.8, 10.1, 11.2], 'colA': [2 , 2, 2, 5, 5, 5, 6, 6, 5, 5, 5], 'colB': [2, 2, 3, 3, 4, 4, 4, 2, 2, 2, 2] }
Я думаю, что цикл здесь не нужен, используйте методы pandas:
df1 = df.melt('Time')
s = df1['value'].ne(df1['value'].shift()).cumsum().rename('g')
out = (df1.groupby(['variable', 'value', s])['Time']
.agg(['first','last'])
.assign(dif=lambda x: x['last'].sub(x['first']))
.groupby(['variable', 'value'])['dif'].sum()
.rename_axis(['Col_name','unique_value'])
.reset_index(name='Duration')
)
print (out)
Col_name unique_value Duration
0 colA 2 3.8
1 colA 3 1.1
2 colA 4 1.8
3 colB 2 1.1
4 colB 5 3.6
5 colB 6 2.3
Вывод с новыми данными из комментария:
df = pd.DataFrame({ 'Time': [1.1, 2.2, 3.4, 4.5, 5.6, 6.2, 7.4, 8.5, 9.8, 10.1, 11.2],
'colA': [2, 2, 2, 5, 5, 5, 6, 6, 5, 5, 5],
'colB': [2, 2, 3, 3, 4, 4, 4, 2, 2, 2, 2] })
df1 = df.melt('Time')
s = df1['value'].ne(df1['value'].shift()).cumsum().rename('g')
out = (df1.groupby(['variable', 'value', s])['Time']
.agg(['first','last'])
.assign(dif=lambda x: x['last'].sub(x['first']))
.groupby(['variable', 'value'])['dif'].sum()
.rename_axis(['Col_name','unique_value'])
.reset_index(name='Duration')
)
print (out)
Col_name unique_value Duration
0 colA 2 2.3
1 colA 5 3.1
2 colA 6 1.1
3 colB 2 3.8
4 colB 3 1.1
5 colB 4 1.8
Как это работает:
Первые значения, которые можно отменить с помощью DataFrame.melt:
df1 = df.melt('Time')
print (df1)
Time variable value
0 1.1 colA 2
1 2.2 colA 2
2 3.4 colA 2
3 4.5 colA 5
4 5.6 colA 5
5 6.2 colA 5
6 7.4 colA 6
7 8.5 colA 6
8 9.8 colA 5
9 10.1 colA 5
10 11.2 colA 5
11 1.1 colB 2
12 2.2 colB 2
13 3.4 colB 3
14 4.5 colB 3
15 5.6 colB 4
16 6.2 colB 4
17 7.4 colB 4
18 8.5 colB 2
19 9.8 colB 2
20 10.1 colB 2
21 11.2 colB 2
Создайте Series
следующих значений:
print (df1.assign(g=s))
Time variable value g
0 1.1 colA 2 1
1 2.2 colA 2 1
2 3.4 colA 2 1
3 4.5 colA 5 2
4 5.6 colA 5 2
5 6.2 colA 5 2
6 7.4 colA 6 3
7 8.5 colA 6 3
8 9.8 colA 5 4
9 10.1 colA 5 4
10 11.2 colA 5 4
11 1.1 colB 2 5
12 2.2 colB 2 5
13 3.4 colB 3 6
14 4.5 colB 3 6
15 5.6 colB 4 7
16 6.2 colB 4 7
17 7.4 colB 4 7
18 8.5 colB 2 8
19 9.8 colB 2 8
20 10.1 colB 2 8
21 11.2 colB 2 8
Агрегировать по последовательным unique_value по вспомогательным s
сериям с помощью GroupBy.first и
GroupBy.last значения по группам:
print (df1.groupby(['variable', 'value', s])['Time']
.agg(['first','last']))
first last
variable value g
colA 2 1 1.1 3.4
5 2 4.5 6.2
4 9.8 11.2
6 3 7.4 8.5
colB 2 5 1.1 2.2
8 8.5 11.2
3 6 3.4 4.5
4 7 5.6 7.4
Вычтите столбцы для разницы:
print (df1.groupby(['variable', 'value', s])['Time']
.agg(['first','last'])
.assign(dif=lambda x: x['last'].sub(x['first'])))
first last dif
variable value g
colA 2 1 1.1 3.4 2.3
5 2 4.5 6.2 1.7
4 9.8 11.2 1.4
6 3 7.4 8.5 1.1
colB 2 5 1.1 2.2 1.1
8 8.5 11.2 2.7
3 6 3.4 4.5 1.1
4 7 5.6 7.4 1.8
И сумма по группам за последний раз:
print (df1.groupby(['variable', 'value', s])['Time']
.agg(['first','last'])
.assign(dif=lambda x: x['last'].sub(x['first']))
.groupby(['variable', 'value'])['dif'].sum())
variable value
colA 2 2.3
5 3.1
6 1.1
colB 2 3.8
3 1.1
4 1.8
Name: dif, dtype: float64
Последнее переименование индексных имен и преобразование в DataFrame
:
s = df1['value'].ne(df1['value'].shift()).cumsum().rename('g')
out = (df1.groupby(['variable', 'value', s])['Time']
.agg(['first','last'])
.assign(dif=lambda x: x['last'].sub(x['first']))
.groupby(['variable', 'value'])['dif'].sum()
.rename_axis(['Col_name','unique_value'])
.reset_index(name='Duration')
)
print (out)
Col_name unique_value Duration
0 colA 2 2.3
1 colA 5 3.1
2 colA 6 1.1
3 colB 2 3.8
4 colB 3 1.1
5 colB 4 1.8
Это удивительное использование панд. Спасибо за ваш ответ
Это потрясающе ! Большое спасибо за молниеносный ответ. Однако у меня есть один вопрос. Я думаю, то, как я вводил столбцы и то, как они выглядели, на самом деле запутало ввод столбцов. Я поменял местами и запустил ваш код, в котором мой результат: уникальные значения для столбца colA: [2 5 6] длительность вывода для этого столбца: [(2, 2.3), (5, 1.7000000000000002), (5, 1.3999999999999986) , (6, 1,0999999999999996)]. Здесь, если вы видите, я намеренно повторил значение 5 с другим числом между ними. Где бы я изменил код, чтобы рассматривать эти 5 вместе?