寻找多个县之间人口数量最大差异?

5
我正在学习Python中的pandas,但似乎无法完成这个问题。有6个人口列,从POPESTIMATE2010到POPESTIMATE2016,我需要找出在这些年份之间人口变化最大的县。(例如,如果该县在5年期间的人口是100、120、80、105、100、130,则其最大变化为|130-80|=50。)
到目前为止,我已经成功将数据转换成了数组和列表,但我不确定哪个更好地解决了这个问题。
import numpy as np
def answer_seven():
    sumlev = census_df.SUMLEV.values == 50
    data = census_df[['POPESTIMATE2010', 'POPESTIMATE2011','POPESTIMATE2012','POPESTIMATE2013','POPESTIMATE2014','POPESTIMATE2015', 'CTYNAME']].values[sumlev]
    s = pd.Series(data[:, 0], [data[:, 1], data[:, 2], data[:, 3], data[:, 4], data[:, 5], data[:, 6]], dtype=np.int64)
return data
answer_seven()

返回数据时的输出:
array([[54660, 55253, 55175, ..., 55290, 55347, 'Autauga County'],
   [183193, 186659, 190396, ..., 199713, 203709, 'Baldwin County'],
   [27341, 27226, 27159, ..., 26815, 26489, 'Barbour County'],
   ..., 
   [21102, 20912, 20989, ..., 20903, 20822, 'Uinta County'],
   [8545, 8469, 8443, ..., 8316, 8328, 'Washakie County'],
   [7181, 7114, 7065, ..., 7185, 7234, 'Weston County']], dtype=object)

当我返回 s 列表时,我得到一个列表:
55253   55175   55038   55290   55347   Autauga County         54660
186659  190396  195126  199713  203709  Baldwin County        183193
27226   27159   26973   26815   26489   Barbour County         27341
22733   22642   22512   22549   22583   Bibb County            22861
57711   57776   57734   57658   57673   Blount County          57373
10629   10606   10628   10829   10696   Bullock County         10887
20673   20408   20261   20276   20154   Butler County          20944
117768  117286  116575  115993  115620  Calhoun County        118437
33993   34075   34153   34052   34123   Chambers County        34098
26080   26023   26084   25995   25859   Cherokee County        25976
43739   43697   43795   43921   43943   Chilton County         43665
13593   13543   13378   13289   13170   Choctaw County         13841
25570   25144   25116   24847   24675   Clarke County          25767
13670   13456   13467   13538   13555   Clay County            13880
14971   14921   15028   15072   15018   Cleburne County        14973
50448   51173   50755   50831   51211   Coffee County          50177
54443   54472   54471   54480   54354   Colbert County         54514
13121   12996   12875   12662   12672   Conecuh County         13208
11348   11195   11059   10807   10724   Coosa County           11758
38060   37818   37830   37888   37835   Covington County       37796
13896   13951   13932   13948   13963   Crenshaw County        13853
80469   80374   80756   81221   82005   Cullman County         80473
50109   50324   49833   49501   49565   Dale County            50358
43178   42777   42021   41662   41131   Dallas County          43803
71387   70942   70869   71012   71130   DeKalb County          71142
80012   80432   80883   81022   81468   Elmore County          79465
38213   38034   37857   37784   37789   Escambia County        38309
104236  104235  103852  103452  103057  Etowah County         104442
17062   16960   16857   16842   16759   Fayette County         17231
31729   31648   31507   31592   31696   Franklin County        31734
                                                               ...  

我查看了多个论坛帖子,但没有找到与此相关的内容。我知道最好的方法是创建一个“最高”列和一个“最低”列,然后找到差异最大的县,但我不知道如何在数组中查找值的最大/最小值。非常感谢帮助!

13个回答

3
我想这应该可以解决你的问题。
temp = census_df[census_df['SUMLEV'] == 50].set_index('CTYNAME')
yrs = ['POPESTIMATE2010','POPESTIMATE2011','POPESTIMATE2012','POPESTIMATE2013', 'POPESTIMATE2014', 'POPESTIMATE2015']
res = temp.loc[:,yrs].max(axis=1) - temp.loc[:,yrs].min(axis=1)
res.idxmax()

2

根据你提到的数据(仅为演示目的限制在几行之内),让我们先将其转换为适当的DataFrame:

from io import StringIO

dataset = """\
55253   55175   55038   55290   55347   Autauga County         54660
186659  190396  195126  199713  203709  Baldwin County        183193
27226   27159   26973   26815   26489   Barbour County         27341
22733   22642   22512   22549   22583   Bibb County            22861
57711   57776   57734   57658   57673   Blount County          57373
"""

df = pd.DataFrame.from_csv(StringIO(dataset), sep='\s{2,}', header=None).reset_index()
df.columns = ['y1', 'y2', 'y3', 'y4', 'y5', 'name', 'y6']
df = df.set_index('name')
df.head()

                y1      y2      y3      y4      y5      y6
name                        
Autauga County  55253   55175   55038   55290   55347   54660
Baldwin County  186659  190396  195126  199713  203709  183193
Barbour County  27226   27159   26973   26815   26489   27341
Bibb County     22733   22642   22512   22549   22583   22861
Blount County   57711   57776   57734   57658   57673   57373

接下来您可以使用numpy的minmax方法计算数据集中的最小值和最大值。然后,您可以创建一个由最大差异组成的新DataFrame。无需在python中使用任何循环,这些循环与pandas或numpy中的优化方法相比速度较慢。

df2 = DataFrame((np.max(df.values, axis=1) - np.min(df.values, axis=1)), index=df.index, columns=['largest_diff'])
df2.head()

                largest_diff
name    
Autauga County  687
Baldwin County  20516
Barbour County  852
Bibb County     349
Blount County   403

数据集有几百行长,我不能简单地复制和粘贴。感谢您的帮助-如果您能更详细地说明如何将您的代码集成到我编写的任何内容中以使其正常工作,我会非常感激。当我尝试使用您提供的内容时,我遇到了“numpy.ndarray”对象没有“set_index”的属性的问题。 - Dick Thompson
不应该使用StringIO。它只是用于演示如何使用panda的from_csv方法。请参考文档。path参数可以是字符串文件路径或文件句柄/StringIO,因此不需要在实际实现中复制和粘贴。此外,from_csv返回一个DataFrame实例,而不是numpy.ndarray。因此,如果使用此方法,则定义了set_index - dotcs

1
如果您的数据一开始就存在于 pandas 数据帧中,则使用 pandas 的 min() 和 max() 方法:
>>> df1
year:   2010    2011    2012    2013    2014
city                    
abilene 47000   2000    31000   72000   47000
boise   44000   55000   68000   17000   63000
calgary 39000   86000   6000    97000   1000
denver  57000   52000   46000   0       43000

>>> df1.T.max()-df1.T.min()
city
abilene    70000
boise      51000
calgary    96000
denver     57000
dtype: int32

这给了我整个集合中最高的数字减去整个集合中最低的数字。我需要找到每行中最高的数字减去每行中最低的数字,然后找到差异最大的县的名称。感激不尽你的澄清。 - Dick Thompson
使用s = (df.T.max() - df.T.min()).sort_values(ascending=False) s.name = 'diff' s.reset_index().ix[0]来查找答案返回的Series中的最大值。 - dotcs
谢谢您的澄清。我输入了那个,但现在出现了“错误-无效语法”的提示? - Dick Thompson
@Richcolumns_to_keep = ['POPESTIMATE2015', 'POPESTIMATE2014', 'POPESTIMATE2013', 'POPESTIMATE2012', 'POPESTIMATE2011', 'POPESTIMATE2010']请问您能否解释一下为什么您的代码输出结果不正确? 错误: x1=census_df[columns_to_keep] x= (x1.T.max()-x1.T.min()).argmax() return census_df.iloc[x].CTYNAME正确: f1 = census_df.set_index(['STNAME', 'CTYNAME']).ix[:, columns_to_keep].stack() f2 = f1.max(level=['STNAME','CTYNAME']) - f1.min(level = ['STNAME', 'CTYNAME']) return f2.idxmax()[1] - piyush-balwani

0
def answer_seven():
    max= census_df[['POPESTIMATE2010', 'POPESTIMATE2011', 'POPESTIMATE2012','POPESTIMATE2013', "POPESTIMATE2014", "POPESTIMATE2015"]].max(axis=1)
    min= census_df[['POPESTIMATE2010', 'POPESTIMATE2011', 'POPESTIMATE2012', 'POPESTIMATE2013', "POPESTIMATE2014", "POPESTIMATE2015"]].min(axis=1)
    absolute_diff = (max-min).abs()
    absolute_diff.index = census_df.index
    census_df['absolute_diff'] = absolute_diff
    return census_df.loc[census_df[census_df['SUMLEV'] == 50]['absolute_diff'].idxmax(), 'CTYNAME']

最好添加一些细节。 - jizhihaoSAMA

0
def answer_seven():

    county = census_df[census_df['SUMLEV']==50]
    county= county.set_index('CTYNAME')
    req_col = ['POPESTIMATE2010',
                           'POPESTIMATE2011',
                           'POPESTIMATE2012',
                           'POPESTIMATE2013',
                           'POPESTIMATE2014',
                           'POPESTIMATE2015']
    countyP= county[req_col]

    res = (countyP[req_col].max(axis=1) - countyP[req_col].min(axis=1)).nlargest(1)


    return res.argmax()

answer_seven()


0

一行就能搞定

def answer_seven():

    cols = [ 'POPESTIMATE2010','POPESTIMATE2011','POPESTIMATE2012','POPESTIMATE2013','POPESTIMATE2014','POPESTIMATE2015' ]

    new = census_df[ census_df['SUMLEV']==50 ].set_index('CTYNAME').apply( lambda x: np.max( x[cols]  - np.min( x[cols]) ), axis=1)

    return new.idxmax()

这很整洁,但与其他解决方案相比速度非常慢。 - kkudi

0

这是我的天真实现。

maxchange = (None,0)
for row in data:
    low = min(row[:-1])
    high = max(row[:-1])
    if high-low > maxchange[1]:
        maxchange = (row[-1], high-low)
print(maxchange)

这个程序使用了在answer_seven中创建的data数组。它会找到每个县的最小值和最大值,并计算出各县之间的最大差异。


谢谢帮忙,但使用你的代码时报错为“在赋值之前引用了局部变量'maxchange'”。希望能得到帮助,告诉我如何整合你的代码使其正常工作。 - Dick Thompson
抱歉,忘记复制 maxchange 的初始化。我已经更新了。 - FamousJameous

0

试试这个:

def df_max_dif (x):

    max_dif = 0

    for ind in x.index:

        max_value = np.max(np.abs(x-x.loc[ind]))

        if max_value > max_dif:

            max_dif = max_value

    return max_dif

df['max_dif'] = np.nan

for indx in df.index:

    df.loc[indx,'max_dif'] = df_max_dif(df.loc[indx].drop('max_dif'))

希望能有所帮助!


谢谢你的帮助,但是我遇到了很多错误。您能否进一步解释一下如何集成您的代码?我一直收到“不支持 str 和 int 操作数类型”的错误提示。 - Dick Thompson
那个错误意味着你正在尝试进行一些不可能的字符串操作,很可能是np.max()或x-x.loc[ind]。要解决这个问题,你需要只传递具有数值的列。 - epattaro
我该怎么做? - Dick Thompson
使用你想选择的列名,而不是只使用 df,来选择 df 中的列,语法为:df[['列名1','列名2',...]]。 - epattaro

0
def my_idea():
    columns_to_keep = ['POPESTIMATE2015','POPESTIMATE2014','POPESTIMATE2013','POPESTIMATE2012','POPESTIMATE2011','POPESTIMATE2010']
    copy_df = census_df[columns_to_keep]

    # max_difference_per_country is a Series with sorted values from high to low
    max_difference_per_country = (copy_df.max(axis=1) - copy_df.min(axis=1)).sort_values(ascending=False)
    # get its index
    index_of_max_difference_per_country = max_difference_per_country.first_valid_index()
    return census_df['CTYNAME'].iloc[index_of_max_difference_per_country]

0

@Tolis 提供的答案并没有排除州名,结果是'Texas'。正确的代码应该像这样:

def answer_seven():
     columns_to_keep = ['POPESTIMATE2015','POPESTIMATE2014','POPESTIMATE2013','POPESTIMATE2012','POPESTIMATE2011','POPESTIMATE2010']
     rows_to_keep = census_df[census_df['SUMLEV'] == 50]
     copy_df = rows_to_keep[columns_to_keep]

     # max_difference_per_country is a Series with sorted values from high to low
     max_difference_per_country = (copy_df.max(axis=1) - copy_df.min(axis=1)).sort_values(ascending=False)

     # get its index
     index_of_max_difference_per_country = max_difference_per_country.first_valid_index()

     return census_df['CTYNAME'].iloc[index_of_max_difference_per_country]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接