根据另一个 df 中的列计算一个 df 中的行数
count number of rows in one df depending on column in another df
好的,我有了第一个数据帧 df1:
|timestamp |ip |
|2022-01-06 11:58:53+00:00|1.1.1.5. |
|2022-01-08 03:56:35+00:00|10.10.10.24|
|2022-01-09 22:29:30+00:00|3.3.3.89. |
|2022-03-08 22:37:52+00:00|8.8.8.88. |
还有第二个数据帧,df2:
|timestamp |other|
|2022-01-07 22:08:59+00:00|other|
|2022-01-07 23:08:59+00:00|other|
|2022-01-09 17:04:09+00:00|other|
|2022-03-05 17:04:09+00:00|other|
我想根据 df1 中的连续 2 个时间戳计算 df2 中有多少行,意思是:
|timestamp |ip |count|
|2022-01-06 11:58:53+00:00|1.1.1.5 |NaN |
|2022-01-08 03:56:35+00:00|10.10.10.24|2 |
|2022-01-09 22:29:30+00:00|3.3.3.89 |1 |
|2022-03-08 22:37:52+00:00|8.8.8.88 |1 |
我尝试的是首先在 df1 中使用之前的时间戳创建另一个列:
df1 = df1.assign(timestamp_b4=df1.timestamp.shift(1)).fillna({'timestamp_b4': df1.timestamp})
这给了我:
|timestamp |ip |timestamp_b4 |
|2022-01-06 11:58:53+00:00|1.1.1.5 |2022-03-08 22:37:52+00:00|
|2022-01-08 03:56:35+00:00|10.10.10.24|2022-01-06 11:58:53+00:00|
|2022-01-09 22:29:30+00:00|3.3.3.89 |2022-01-08 03:56:35+00:00|
|2022-03-08 22:37:52+00:00|8.8.8.88 |2022-01-09 22:29:30+00:00|
然后做一些
s = (df2[df2['timestamp'].between(df1['timestamp'], df1['timestamp_b4'])].size())
但不幸的是它不起作用,因为 pandas 需要比较相同标记的对象。
有什么好的pandas/pythonic方法吗?
谢谢
试试这个,这是您可以如何找到解决方案的示例
import pandas as pd
table1 = {
'timestamp':['2022-01-06 11:58:53+00:00','2022-01-08 03:56:35+00:00',
'2022-01-09 22:29:30+00:00','2022-03-08 22:37:52+00:00'],
'other':['other','other','other','other']
}
df1 = pd.DataFrame(table1)
table2 = {
'timestamp':['2022-01-07 23:08:59+00:00','2022-01-07 22:08:59+00:00',
'2022-03-05 17:04:09+00:00','2022-01-09 17:04:09+00:00'],
'ip':['1.1.1.5.','10.10.10.24','3.3.3.89.','8.8.8.88.']
}
df2 = pd.DataFrame(table2)
print(f'\n\n-------------df1-----------\n\n')
print(df2)
print(f'\n\n-------------df2-----------\n\n')
print(df1)
listdf1 = df1['timestamp'].values.tolist()
def func(line):
cont = df1.loc[df1['timestamp'].str.contains(line[0][:7], case = False)]
temp = line.name - 1
if temp == -1:
temp = 0
try :
cont = [cont['timestamp'].iloc[temp],line[0]]
except:
cont = [line[0],line[0]]
cont2 = df2['timestamp'].loc[df2['timestamp'].str.contains(line[0][:7], case = False)]
repetitions = 0
for x in cont2:
if int(x[8:10]) >= int(cont[0][8:10]) and int(x[8:10]) <= int(cont[1][8:10]) and int(x[8:10]) <= int(line[0][8:10]):
repetitions += 1
return repetitions
print(f'\n\n-------------BREAK-----------\n\n')
df1['count'] = df1.apply(func, axis = 1)
print(df1)
这是一种方法。请注意,来自 df1 的列保留在最终输出 df:
从具有附加列的此 df1 开始:
timestamp ip another_col
0 2022-01-06 11:58:53+00:00 1.1.1.5. val_1
1 2022-01-08 03:56:35+00:00 10.10.10.24 val_2
2 2022-01-09 22:29:30+00:00 3.3.3.89. val_3
3 2022-03-08 22:37:52+00:00 8.8.8.88. val_4
df1.merge(df2, on='timestamp', how='outer').sort_values('timestamp') \
.assign(c1=df1.loc[~df1['ip'].isna()]['ip'], c2=lambda x: x['c1'].bfill() ) \
.assign(count=lambda x: x.groupby('c2').apply('count').reset_index(drop=True)['timestamp']-1) \
.drop(['other','c1','c2'], axis=1).dropna().astype({'count': 'int32'})
timestamp ip another_col count
0 2022-01-06 11:58:53+00:00 1.1.1.5. val_1 0
1 2022-01-08 03:56:35+00:00 10.10.10.24 val_2 2
2 2022-01-09 22:29:30+00:00 3.3.3.89. val_3 1
3 2022-03-08 22:37:52+00:00 8.8.8.88. val_4 1
请注意,another_col
保留在输出中。
此方法合并,然后按时间戳排序,然后创建另一列 - c2 - 用于复制 df1 时间戳,然后根据 df2 时间戳回填它。从那里开始,实例按 df1 时间戳(反映在 c2 列中)进行分组并进行计数。换句话说,df1 时间戳的回填允许它用作分组键来计算前面的 df2 时间戳。之后 df 被修剪回符合输出要求。
另请注意,使用这种方法,数据帧需要像我示例中的当前索引一样编入 0-n 索引。
def time_compare(df1,df2):
return [np.sum((df1['timestamp'].values[i-1] < df2['timestamp'].values) & (df1['timestamp'].values[i] > df2['timestamp'].values)) for i in range(len(df1.timestamp))]
df2.join(pd.Series(time_compare(df1,df2), name='Count'))
奇怪我不能post数据帧像往常一样输出:
index
timestamp
other
Count
0
2022-01-07 22:08:5900:00
other
0
1
2022-01-07 23:08:5900:00
other
2
2
2022-01-09 17:04:0900:00
other
1
3
2022-03-05 17:04:0900:00
other
1
好的,最后,这就是我所做的。我使用了@Drakax 的回答。
我用以前的时间戳创建了一个列
df1 = df1.assign(previous_deconnection=df1.timestamp.shift(1)).fillna({'previous_deconnection': df1.timestamp})
然后我设置第一行值,
df1['previous_deconnection'].iloc[0]=pd.to_datetime('2022-01-01 00:00:00+00:00')
然后我将此函数应用于 df1 的每一行
def time_compare(a,b):
return len(b[((b['timestamp'] >= a['previous_deconnection']) & (b['timestamp'] <= a['timestamp']))])
df1['Count'] = df1.apply(lambda row: time_compare(row, df2), axis=1)
好的,我有了第一个数据帧 df1:
|timestamp |ip |
|2022-01-06 11:58:53+00:00|1.1.1.5. |
|2022-01-08 03:56:35+00:00|10.10.10.24|
|2022-01-09 22:29:30+00:00|3.3.3.89. |
|2022-03-08 22:37:52+00:00|8.8.8.88. |
还有第二个数据帧,df2:
|timestamp |other|
|2022-01-07 22:08:59+00:00|other|
|2022-01-07 23:08:59+00:00|other|
|2022-01-09 17:04:09+00:00|other|
|2022-03-05 17:04:09+00:00|other|
我想根据 df1 中的连续 2 个时间戳计算 df2 中有多少行,意思是:
|timestamp |ip |count|
|2022-01-06 11:58:53+00:00|1.1.1.5 |NaN |
|2022-01-08 03:56:35+00:00|10.10.10.24|2 |
|2022-01-09 22:29:30+00:00|3.3.3.89 |1 |
|2022-03-08 22:37:52+00:00|8.8.8.88 |1 |
我尝试的是首先在 df1 中使用之前的时间戳创建另一个列:
df1 = df1.assign(timestamp_b4=df1.timestamp.shift(1)).fillna({'timestamp_b4': df1.timestamp})
这给了我:
|timestamp |ip |timestamp_b4 |
|2022-01-06 11:58:53+00:00|1.1.1.5 |2022-03-08 22:37:52+00:00|
|2022-01-08 03:56:35+00:00|10.10.10.24|2022-01-06 11:58:53+00:00|
|2022-01-09 22:29:30+00:00|3.3.3.89 |2022-01-08 03:56:35+00:00|
|2022-03-08 22:37:52+00:00|8.8.8.88 |2022-01-09 22:29:30+00:00|
然后做一些
s = (df2[df2['timestamp'].between(df1['timestamp'], df1['timestamp_b4'])].size())
但不幸的是它不起作用,因为 pandas 需要比较相同标记的对象。
有什么好的pandas/pythonic方法吗?
谢谢
试试这个,这是您可以如何找到解决方案的示例
import pandas as pd
table1 = {
'timestamp':['2022-01-06 11:58:53+00:00','2022-01-08 03:56:35+00:00',
'2022-01-09 22:29:30+00:00','2022-03-08 22:37:52+00:00'],
'other':['other','other','other','other']
}
df1 = pd.DataFrame(table1)
table2 = {
'timestamp':['2022-01-07 23:08:59+00:00','2022-01-07 22:08:59+00:00',
'2022-03-05 17:04:09+00:00','2022-01-09 17:04:09+00:00'],
'ip':['1.1.1.5.','10.10.10.24','3.3.3.89.','8.8.8.88.']
}
df2 = pd.DataFrame(table2)
print(f'\n\n-------------df1-----------\n\n')
print(df2)
print(f'\n\n-------------df2-----------\n\n')
print(df1)
listdf1 = df1['timestamp'].values.tolist()
def func(line):
cont = df1.loc[df1['timestamp'].str.contains(line[0][:7], case = False)]
temp = line.name - 1
if temp == -1:
temp = 0
try :
cont = [cont['timestamp'].iloc[temp],line[0]]
except:
cont = [line[0],line[0]]
cont2 = df2['timestamp'].loc[df2['timestamp'].str.contains(line[0][:7], case = False)]
repetitions = 0
for x in cont2:
if int(x[8:10]) >= int(cont[0][8:10]) and int(x[8:10]) <= int(cont[1][8:10]) and int(x[8:10]) <= int(line[0][8:10]):
repetitions += 1
return repetitions
print(f'\n\n-------------BREAK-----------\n\n')
df1['count'] = df1.apply(func, axis = 1)
print(df1)
这是一种方法。请注意,来自 df1 的列保留在最终输出 df:
从具有附加列的此 df1 开始:
timestamp ip another_col
0 2022-01-06 11:58:53+00:00 1.1.1.5. val_1
1 2022-01-08 03:56:35+00:00 10.10.10.24 val_2
2 2022-01-09 22:29:30+00:00 3.3.3.89. val_3
3 2022-03-08 22:37:52+00:00 8.8.8.88. val_4
df1.merge(df2, on='timestamp', how='outer').sort_values('timestamp') \
.assign(c1=df1.loc[~df1['ip'].isna()]['ip'], c2=lambda x: x['c1'].bfill() ) \
.assign(count=lambda x: x.groupby('c2').apply('count').reset_index(drop=True)['timestamp']-1) \
.drop(['other','c1','c2'], axis=1).dropna().astype({'count': 'int32'})
timestamp ip another_col count
0 2022-01-06 11:58:53+00:00 1.1.1.5. val_1 0
1 2022-01-08 03:56:35+00:00 10.10.10.24 val_2 2
2 2022-01-09 22:29:30+00:00 3.3.3.89. val_3 1
3 2022-03-08 22:37:52+00:00 8.8.8.88. val_4 1
请注意,another_col
保留在输出中。
此方法合并,然后按时间戳排序,然后创建另一列 - c2 - 用于复制 df1 时间戳,然后根据 df2 时间戳回填它。从那里开始,实例按 df1 时间戳(反映在 c2 列中)进行分组并进行计数。换句话说,df1 时间戳的回填允许它用作分组键来计算前面的 df2 时间戳。之后 df 被修剪回符合输出要求。
另请注意,使用这种方法,数据帧需要像我示例中的当前索引一样编入 0-n 索引。
def time_compare(df1,df2):
return [np.sum((df1['timestamp'].values[i-1] < df2['timestamp'].values) & (df1['timestamp'].values[i] > df2['timestamp'].values)) for i in range(len(df1.timestamp))]
df2.join(pd.Series(time_compare(df1,df2), name='Count'))
奇怪我不能post数据帧像往常一样输出:
index | timestamp | other | Count |
---|---|---|---|
0 | 2022-01-07 22:08:5900:00 | other | 0 |
1 | 2022-01-07 23:08:5900:00 | other | 2 |
2 | 2022-01-09 17:04:0900:00 | other | 1 |
3 | 2022-03-05 17:04:0900:00 | other | 1 |
好的,最后,这就是我所做的。我使用了@Drakax 的回答。
我用以前的时间戳创建了一个列
df1 = df1.assign(previous_deconnection=df1.timestamp.shift(1)).fillna({'previous_deconnection': df1.timestamp})
然后我设置第一行值,
df1['previous_deconnection'].iloc[0]=pd.to_datetime('2022-01-01 00:00:00+00:00')
然后我将此函数应用于 df1 的每一行
def time_compare(a,b):
return len(b[((b['timestamp'] >= a['previous_deconnection']) & (b['timestamp'] <= a['timestamp']))])
df1['Count'] = df1.apply(lambda row: time_compare(row, df2), axis=1)