如何按值对多个列执行有序选择

时间:2019-01-06 05:52:40

标签: python python-3.x pandas selection

我有一个包含月份和年份列的数据框。两者都包含字符串,即“ September”和“ 2013”​​。如何选择2013年9月至2008年5月之间的所有行?

df1 = stats_month_census_2[(stats_month_census_2['year'] <= '2013')
                 & (stats_month_census_2['year'] >= '2008')]

df2 = df1[...]

在上面的代码之后,我打算再次做同样的事情,但是我很难拿出聪明的代码来简单地删除时间比2013年9月(“十月至十二月”)高的行。并且在2008年5月以下。我可以轻松地对此进行硬编码,但是必须有一种更Python的方式来实现此目的...

4 个答案:

答案 0 :(得分:3)

您可以使用pd.to_datetime

轻松地将列转换为DateTime列
>>df    
    month       year
0   January     2000
1   April       2001
2   July        2002
3   February    2010
4   February    2018
5   March       2014
6   June        2012
7   June        2011
8   May         2009
9   November    2016


>>df['date'] = pd.to_datetime(df['month'].astype(str) + '-' + df['year'].astype(str), format='%B-%Y')
>>df

        month   year    date
0   January     2000    2000-01-01
1   April       2001    2001-04-01
2   July        2002    2002-07-01
3   February    2010    2010-02-01
4   February    2018    2018-02-01
5   March       2014    2014-03-01
6   June        2012    2012-06-01
7   June        2011    2011-06-01
8   May         2009    2009-05-01
9   November    2016    2016-11-01

>>df[(df.date <= "2013-09") & (df.date >= "2008-05") ]
       month    year    date
3   February    2010    2010-02-01
6   June        2012    2012-06-01
7   June        2011    2011-06-01
8   May         2009    2009-05-01

答案 1 :(得分:3)

或者,您可以按照帖子“选择2013年9月至2008年5月之间的所有行” 中的说明,尝试查找2008年至2013年之间的行数。   然后使用pandas.Series.between

从@jezrael借用的数据集。

用于演示目的的数据框:

>>> stats_month_census_2
   year      month  data
0  2008      April     1
1  2008        May     3
2  2008       June     4
3  2013  September     6
4  2013    October     5
5  2014   November     6
6  2014   December     7

使用pandas.Series.between()

>>> stats_month_census_2[stats_month_census_2['year'].between(2008, 2013, inclusive=True)]
   year      month  data
0  2008      April     1
1  2008        May     3
2  2008       June     4
3  2013  September     6
4  2013    October     5

如果只是datetime格式的问题,您可以尝试以下操作:

>>> stats_month_census_2[stats_month_census_2['year'].between('2008-05', '2013-09', inclusive=True)]
        year      month  data
1 2008-05-01        May     3
2 2008-06-01       June     4
3 2013-09-01  September     6

使用DataFame.query:

>>> stats_month_census_2.query('"2008-05" <= year <= "2013-09"')
        year      month  data
1 2008-05-01        May     3
2 2008-06-01       June     4
3 2013-09-01  September     6

使用isin方法:选择两个日期之间的行

>>> stats_month_census_2[stats_month_census_2['year'].isin(pd.date_range('2008-05-01', '2013-09-01'))]
        year      month  data
1 2008-05-01        May     3
2 2008-06-01       June     4
3 2013-09-01  September     6

或者,甚至您也可以像下面那样通过。

>>> stats_month_census_2[stats_month_census_2['year'].isin(pd.date_range('2008-05', '2013-09'))]
        year      month  data
1 2008-05-01        May     3
2 2008-06-01       June     4
3 2013-09-01  September     6

使用 loc方法,具体方法是根据索引的开始和结束日期进行划分。

Start = stats_month_census_2[stats_month_census_2['year'] =='2008-05'].index[0]
End = stats_month_census_2[stats_month_census_2['year']=='2013-09'].index[0]

>>> stats_month_census_2.loc[Start:End]
        year      month  data
1 2008-05-01        May     3
2 2008-06-01       June     4
3 2013-09-01  September     6

注意:出于好奇,正如@jezrael在评论中要求的那样,我要添加如何将year列转换为日期时间格式:

因为我们有下面的示例DataFrame,其中有两个不同的列yearmonth,其中year列只有Years,month列是文字字符串格式,所以,首先我们需要转换String转换为int形式,或通过使用pd.to_datetime方法为所有熊猫分配一天作为1,将年或月加起来或加在一起。

df
   year      month  data
0  2008      April     1
1  2008        May     3
2  2008       June     4
3  2013  September     6
4  2013    October     5
5  2014   November     6
6  2014   December     7

上面是日期时间转换之前的原始DataFrame。所以,我采用以下方法,这是我随时间在vi SO本身中学到的。

1-首先,将month名称转换为int形式,然后轻松地将其分配到名为Month的新列中。因此,我们以后可以将其用于转换。

df['Month'] = pd.to_datetime(df.month, format='%B').dt.month

2-其次,或者最后直接通过将datetime列本身直接分配,将year列直接转换为适当的year格式,这是我们可以说的一种地方。

df['Date'] = pd.to_datetime(df[['year', 'Month']].assign(Day=1))
  

现在,所需的DataFrame和year列为日期时间格式:

print(df)
        year      month  data  Month
0 2008-04-01      April     1      4
1 2008-05-01        May     3      5
2 2008-06-01       June     4      6
3 2013-09-01  September     6      9
4 2013-10-01    October     5     10
5 2014-11-01   November     6     11
6 2014-12-01   December     7     12

答案 2 :(得分:2)

您可以创建DatetimeIndex,然后按partial string indexing进行选择:

stats_month_census_2 = pd.DataFrame({
    'year': [2008, 2008, 2008, 2013,2013],
    'month': ['April','May','June','September','October'],
    'data':[1,3,4,6,5]
})
print (stats_month_census_2)
   year      month  data
0  2008      April     1
1  2008        May     3
2  2008       June     4
3  2013  September     6
4  2013    October     5

s = stats_month_census_2.pop('year').astype(str) + stats_month_census_2.pop('month')
#if need year and month columns
#s = stats_month_census_2['year'].astype(str) + stats_month_census_2['month']
stats_month_census_2.index = pd.to_datetime(s, format='%Y%B')
print (stats_month_census_2)
            data
2008-04-01     1
2008-05-01     3
2008-06-01     4
2013-09-01     6
2013-10-01     5

print (stats_month_census_2['2008':'2013'])
            data
2008-04-01     1
2008-05-01     3
2008-06-01     4
2013-09-01     6
2013-10-01     5    

print (stats_month_census_2['2008-05':'2013-09'])
            data
2008-05-01     3
2008-06-01     4
2013-09-01     6

或创建列并将betweenboolean indexing结合使用:

s = stats_month_census_2['year'].astype(str) + stats_month_census_2['month']
stats_month_census_2['date'] = pd.to_datetime(s, format='%Y%B')
print (stats_month_census_2)
   year      month  data       date
0  2008      April     1 2008-04-01
1  2008        May     3 2008-05-01
2  2008       June     4 2008-06-01
3  2013  September     6 2013-09-01
4  2013    October     5 2013-10-01

df = stats_month_census_2[stats_month_census_2['date'].between('2008-05', '2013-09')]
print (df)
   year      month  data       date
1  2008        May     3 2008-05-01
2  2008       June     4 2008-06-01
3  2013  September     6 2013-09-01

不幸的是,在某些年份之前,无法通过datetime列使用这种方式,因此需要在pygo列中使用year解决方案:

#wrong output
df = stats_month_census_2[stats_month_census_2['date'].between('2008', '2013')]
print (df)

   year  month  data       date
0  2008  April     1 2008-04-01
1  2008    May     3 2008-05-01
2  2008   June     4 2008-06-01

答案 3 :(得分:2)

另一种解决方案:

让我们假设df如下图所示:

    series      name       Month     Year
0   fertility   rate       May       2008
1   CO2         emissions  June      2009
2   fertility   rate       September 2013
3   fertility   rate       October   2013
4   CO2         emissions  December  2014

创建日历字典映射并保存在新列中

import calendar
d = dict((v,k) for k,v in enumerate(calendar.month_abbr))
stats_month_census_2['month_int'] = stats_month_census_2.Month.apply(lambda x: x[:3]).map(d)

>>stats_month_census_2

    series      name      Month     Year    month_int
0   fertility   rate      May       2008    5
1   CO2         emissions June      2009    6
2   fertility   rate      September 2013    9
3   fertility   rate      October   2013    10
4   CO2         emissions December  2014    12

使用进行过滤 series.between()

stats_month_census_2[stats_month_census_2.month_int.between(5,9,inclusive=True) & stats_month_census_2.Year.between(2008,2013,inclusive=True)]

输出:

    series      name      Month      Year   month_int
0   fertility   rate      May        2008   5
1   CO2         emissions June       2009   6
2   fertility   rate      September  2013   9