Python 如何在pandas中基于多个条件匹配和计数行?

Python 如何在pandas中基于多个条件匹配和计数行?,python,pandas,dataframe,Python,Pandas,Dataframe,我目前正在处理一个csv数据集,如下所示(请参见下面的测试df): 这些基本上是移动设备位置记录。“标识符”唯一标识移动设备,“from_city”和“to_city”是相应的出发和到达城市。例如,对于标识符“A1”,此人于1月2日(记录编号2)离开渥太华前往伦敦,并于1月3日(记录编号5)返回。而对于标识符为A2、B1、B2、B3和B6的记录,由于没有伦敦到渥太华的记录,它们将被视为不返回 最后,我想做的是找出所有出发和返回的比赛,并计算每对从城市到城市的比赛。例如: 从渥太华到伦敦:总共1

我目前正在处理一个csv数据集,如下所示(请参见下面的测试df):

这些基本上是移动设备位置记录。“标识符”唯一标识移动设备,“from_city”和“to_city”是相应的出发和到达城市。例如,对于标识符“A1”,此人于1月2日(记录编号2)离开渥太华前往伦敦,并于1月3日(记录编号5)返回。而对于标识符为A2、B1、B2、B3和B6的记录,由于没有伦敦到渥太华的记录,它们将被视为不返回

最后,我想做的是找出所有出发和返回的比赛,并计算每对从城市到城市的比赛。例如:

从渥太华到伦敦:总共100次,80次在3天内返回,10次在3天后返回,10次没有返回

我想我需要使用标识符和其他列在pandas中进行groupby。但问题是如何在标识符组中识别返回匹配

基本上,标准应该是:

  • 相同标识符
  • 从_市和到_市在两个记录之间颠倒
  • 返回时间应晚于出发时间
另外,如何在3天内嵌入标准

提前感谢您的帮助

以下是用于测试的数据帧:

df = pd.DataFrame({
    'Identifier': ['A1', 'A2', 'A3', 'A1', 'A3', 'B1', 'C3', 'B2', 'B3', 'B6', 'C3'],
    'OS': ['iphone', 'iphone', 'iphone', 'iphone', 'iphone', 'iphone', 'iphone', 'iphone', 'iphone', 'iphone', 'iphone'],
    'from_city': ['ottawa', 'ottawa', 'ottawa', 'london', 'london', 'ottawa', 'ottawa', 'ottawa', 'ottawa', 'ottawa', 'london'],
    'to_city': ['london', 'london', 'london', 'ottawa', 'ottawa', 'london', 'london', 'london', 'london', 'london', 'ottawa'],
    'time': ['1/2/2017 21:00', '1/2/2017 20:00', '12/24/2016 13:00', '1/3/2017 21:00', '1/6/2017 0:00',
            '12/10/2016 17:00', '12/22/2016 21:00', '12/17/2016 23:00', '12/14/2016 19:00', '12/20/2016 18:00', '1/3/2017 0:00']
})

注:上述img第5行中的日期应为“2017年1月3日”,该日期在上述代码中固定。

如果每个标识符在您的数据集中只有一次往返,则此方法可行。另外,我将示例数据框中
time
列的第4个元素的年份更改为2017年

首先将
df['time']
转换为日期时间

duration=df.groupby('Identifier')['time'].apply(lambda x:max(list(x))-min(list(x))

然后在
标识符上使用groupby:

duration=df.groupby('Identifier')['time'].apply(lambda x:max(list(x))-min(list(x))

持续时间
现在看起来像:

A1 1天00:00:00
A2 0天00:00:00
A3 12天11:00:00
B1 0天00:00:00
B2 0天00:00:00
B3 0天00:00:00
B6 0天00:00:00
C3 11天03:00:00

现在选择大于0天但小于3天的行

duration[(duration>pd.Timedelta(days=0))&(duration
返回值:

    Identifier  OS  from_city   timestamp_leave to_city timestamp_back  duration    group
1   A2  iphone  ottawa  2017-01-02 20:00:00 london  NaT NaN NaN
2   A3  iphone  ottawa  2016-12-24 13:00:00 london  2017-01-06 00:00:00 12.0    (10, 100]
3   A1  iphone  london  2016-01-03 21:00:00 ottawa  2017-01-02 21:00:00 365.0   NaN
5   B1  iphone  ottawa  2016-12-10 17:00:00 london  NaT NaN NaN
6   C3  iphone  ottawa  2016-12-22 21:00:00 london  2017-01-03 00:00:00 11.0    (10, 100]
7   B2  iphone  ottawa  2016-12-17 23:00:00 london  NaT NaN NaN
8   B3  iphone  ottawa  2016-12-14 19:00:00 london  NaT NaN NaN
9   B6  iphone  ottawa  2016-12-20 18:00:00 london  NaT NaN NaN

我终于想出了一个办法:

def combine_cities(row):
    if row['from_city'] < row['to_city']:
        return row['from_city'] + ', ' + row['to_city']
    else:
        return row['to_city'] + ', ' + row['from_city']

df['cities'] = df.apply(combine_cities, axis=1)

def count_return(grp):
    if grp.nunique() == 1:
        return np.nan
    else:
        return 'return found'

df.groupby(['cities', 'Identifier'])['from_city'].apply(count_return).dropna()
def合并城市(世界其他地区):
如果第['from_city']
您的回答似乎没有考虑返回因素-城市对需要反转,如果第一个记录是“渥太华伦敦”,则返回记录基本上应该是“伦敦渥太华”。这是有道理的,但您的数据集不存在这种情况。您可以更新您的描述或示例数据框吗?我补充了这一澄清:“对于标识符为A2、B1、B2、B3和B6的记录,由于没有伦敦到渥太华的记录,它们将被视为不返回。”谢谢!我在运行您的代码时出错…“TypeError:不支持的操作数类型-:'str'和'str'。您能给我一些进一步的指导吗?我认为是关于'time'列的类型。可能您的'time'类型是字符串。尝试将
df['time']=pd.添加到\u datetime(df['time'],格式='%m/%d/%Y%H:%m'))
在代码开头。谢谢!我试过这个“df['timestamp']=pd.to\u datetime(df['timestamp'])”,但仍然得到:KeyError:“time\u leave”我得到了。因为
“time\u leave”和
“time\u back”
是添加到列名
“time”
的后缀。因此生成列名
“time\u leave”和
“time\u back”
。看起来你
“time”
列的名称是
“timestamp”
,所以你的另外两个Generic列应该被称为
'timestamp\u leave'
'timestamp\u back'
。再次感谢!这次没有错误,但我想知道我应该如何检查最终结果?即如何计算返回的数量?
def combine_cities(row):
    if row['from_city'] < row['to_city']:
        return row['from_city'] + ', ' + row['to_city']
    else:
        return row['to_city'] + ', ' + row['from_city']

df['cities'] = df.apply(combine_cities, axis=1)

def count_return(grp):
    if grp.nunique() == 1:
        return np.nan
    else:
        return 'return found'

df.groupby(['cities', 'Identifier'])['from_city'].apply(count_return).dropna()