Adding new column to existing DataFrame in Python pandas
我有以下索引数据框,其中列和行不是连续的数字:
1 2 3 4 | a b c d 2 0.671399 0.101208 -0.181532 0.241273 3 0.446172 -0.243316 0.051767 1.577318 5 0.614758 0.075793 -0.451460 -0.012493 |
我想在现有的数据帧中添加一个新列,即
1 2 3 4 | 0 -0.335485 1 -1.166658 2 -0.385571 dtype: float64 |
我试过不同版本的
使用原始DF1索引创建序列:
1 | df1['e'] = Series(np.random.randn(sLength), index=df1.index) |
编辑2015有人报告说用这个代码得到了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | >>> sLength = len(df1['a']) >>> df1 a b c d 6 -0.269221 -0.026476 0.997517 1.294385 8 0.917438 0.847941 0.034235 -0.448948 >>> df1['e'] = p.Series(np.random.randn(sLength), index=df1.index) >>> df1 a b c d e 6 -0.269221 -0.026476 0.997517 1.294385 1.757167 8 0.917438 0.847941 0.034235 -0.448948 2.228131 >>> p.version.short_version '0.16.1' |
1 2 3 4 5 6 | >>> df1.loc[:,'f'] = p.Series(np.random.randn(sLength), index=df1.index) >>> df1 a b c d e f 6 -0.269221 -0.026476 0.997517 1.294385 1.757167 -0.050927 8 0.917438 0.847941 0.034235 -0.448948 2.228131 0.006109 >>> |
事实上,这是目前大熊猫文献中描述的更有效的方法。
编辑2017
正如注释和@alexander所指出的,当前将系列值作为数据帧新列添加的最佳方法可能是使用
1 | df1 = df1.assign(e=p.Series(np.random.randn(sLength)).values) |
这是添加新列的简单方法:
I would like to add a new column, 'e', to the existing data frame and do not change anything in the data frame. (The series always got the same length as a dataframe.)
我假设
最简单的方法是启动一个名为
1 | df['e'] = e.values |
分配(熊猫0.16.0+)
从pandas 0.16.0开始,您还可以使用
1 | df1 = df1.assign(e=e.values) |
根据此示例(也包括
1 2 3 4 5 | df = pd.DataFrame({'a': [1, 2], 'b': [3, 4]}) >>> df.assign(mean_a=df.a.mean(), mean_b=df.b.mean()) a b mean_a mean_b 0 1 3 1.5 3.5 1 2 4 1.5 3.5 |
在您的示例中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | np.random.seed(0) df1 = pd.DataFrame(np.random.randn(10, 4), columns=['a', 'b', 'c', 'd']) mask = df1.applymap(lambda x: x <-0.7) df1 = df1[-mask.any(axis=1)] sLength = len(df1['a']) e = pd.Series(np.random.randn(sLength)) >>> df1 a b c d 0 1.764052 0.400157 0.978738 2.240893 2 -0.103219 0.410599 0.144044 1.454274 3 0.761038 0.121675 0.443863 0.333674 7 1.532779 1.469359 0.154947 0.378163 9 1.230291 1.202380 -0.387327 -0.302303 >>> e 0 -1.048553 1 -1.420018 2 -1.706270 3 1.950775 4 -0.509652 dtype: float64 df1 = df1.assign(e=e.values) >>> df1 a b c d e 0 1.764052 0.400157 0.978738 2.240893 -1.048553 2 -0.103219 0.410599 0.144044 1.454274 -1.420018 3 0.761038 0.121675 0.443863 0.333674 -1.706270 7 1.532779 1.469359 0.154947 0.378163 1.950775 9 1.230291 1.202380 -0.387327 -0.302303 -0.509652 |
在这里可以找到这个新特性首次引入时的描述。
直接通过numpy执行此操作将是最有效的:
1 | df1['e'] = np.random.randn(sLength) |
注:我最初(非常老)的建议是使用
1 | df1['e'] = df1['a'].map(lambda x: np.random.random()) |
在最近的熊猫版本中,使用df.assign似乎是可行的方法:
它不产生
超简单列分配
熊猫数据帧是作为列的有序dict实现的。
这就是说,
例如,只需使用
1 2 3 4 5 6 7 8 9 10 11 12 13 | size name color 0 big rose red 1 small violet blue 2 small tulip red 3 small harebell blue df['protected'] = ['no', 'no', 'no', 'yes'] size name color protected 0 big rose red no 1 small violet blue no 2 small tulip red no 3 small harebell blue yes |
请注意,即使关闭了数据帧的索引,也可以这样做。
1 2 3 4 5 6 7 | df.index = [3,2,1,0] df['protected'] = ['no', 'no', 'no', 'yes'] size name color protected 3 big rose red no 2 small violet blue no 1 small tulip red no 0 small harebell blue yes |
[]=该走了,但要小心!
但是,如果您有一个
1 2 3 4 5 6 | df['protected'] = pd.Series(['no', 'no', 'no', 'yes']) size name color protected 3 big rose red yes 2 small violet blue no 1 small tulip red no 0 small harebell blue no |
这是因为默认情况下,
当您使用
这很快就会引起认知失调,因为
如果您有一个
你可以把
1 | df['protected'] = pd.Series(['no', 'no', 'no', 'yes']).values |
或
1 | df['protected'] = list(pd.Series(['no', 'no', 'no', 'yes'])) |
但这并不十分明确。
一些编码人员可能会过来说:"嘿,这看起来是多余的,我会把它优化掉。"
显式方式将
1 | df['protected'] = pd.Series(['no', 'no', 'no', 'yes'], index=df.index) |
或者更现实地说,您可能已经有了一个
1 2 3 4 5 6 7 | protected_series = pd.Series(['no', 'no', 'no', 'yes']) protected_series.index = df.index 3 no 2 no 1 no 0 yes |
现在可以分配
1 2 3 4 5 6 7 | df['protected'] = protected_series size name color protected 3 big rose red no 2 small violet blue no 1 small tulip red no 0 small harebell blue yes |
与
由于索引不一致是问题所在,如果您认为数据帧的索引不应该指示事情,那么您可以简单地删除索引,这应该更快,但它不是很干净,因为您的函数现在可能会做两件事。
1 2 3 4 5 6 7 8 9 | df.reset_index(drop=True) protected_series.reset_index(drop=True) df['protected'] = protected_series size name color protected 0 big rose red no 1 small violet blue no 2 small tulip red no 3 small harebell blue yes |
关于
虽然
1 2 3 4 5 6 | df.assign(protected=pd.Series(['no', 'no', 'no', 'yes'])) size name color protected 3 big rose red yes 2 small violet blue no 1 small tulip red no 0 small harebell blue no |
只需注意你的专栏不叫
1 2 | df.assign(self=pd.Series(['no', 'no', 'no', 'yes']) TypeError: assign() got multiple values for keyword argument 'self' |
你可以说,"那么,我就不使用
如果要将整个新列设置为初始基值(如
这实际上会将"对象"类型分配给单元。所以稍后您可以自由地将复杂的数据类型(如列表)放入单个单元格中。
我得到了可怕的
1 | df.insert(len(df.columns), 'e', pd.Series(np.random.randn(sLength), index=df.index)) |
这样可以很好地在末尾插入列。我不知道它是否是最有效的,但我不喜欢警告信息。我认为有更好的解决方案,但我找不到,我认为这取决于索引的某些方面。注意事项。这只起作用一次,如果试图覆盖现有列,将给出错误消息。请注意,如上所述,0.16.0中的赋值是最佳解决方案。参见文档http://pandas.pydata.org/pandas docs/stable/generated/pandas.dataframe.assign.html pandas.dataframe.assign适用于不覆盖中间值的数据流类型。
最简单的方法:
1 2 3 | data['new_col'] = list_of_values data.loc[ : , 'new_col'] = list_of_values |
如果要添加的列是一个系列变量,则只需:
1 | df["new_columns_name"]=series_variable_name #this will do it for you |
即使替换现有列,也能很好地工作。只需键入与要替换的列相同的新列名称。它只会用新的序列数据覆盖现有列数据。
Foolproof:
1 | df.loc[:, 'NewCol'] = 'New_Val' |
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | df = pd.DataFrame(data=np.random.randn(20, 4), columns=['A', 'B', 'C', 'D']) df A B C D 0 -0.761269 0.477348 1.170614 0.752714 1 1.217250 -0.930860 -0.769324 -0.408642 2 -0.619679 -1.227659 -0.259135 1.700294 3 -0.147354 0.778707 0.479145 2.284143 4 -0.529529 0.000571 0.913779 1.395894 5 2.592400 0.637253 1.441096 -0.631468 6 0.757178 0.240012 -0.553820 1.177202 7 -0.986128 -1.313843 0.788589 -0.707836 8 0.606985 -2.232903 -1.358107 -2.855494 9 -0.692013 0.671866 1.179466 -1.180351 10 -1.093707 -0.530600 0.182926 -1.296494 11 -0.143273 -0.503199 -1.328728 0.610552 12 -0.923110 -1.365890 -1.366202 -1.185999 13 -2.026832 0.273593 -0.440426 -0.627423 14 -0.054503 -0.788866 -0.228088 -0.404783 15 0.955298 -1.430019 1.434071 -0.088215 16 -0.227946 0.047462 0.373573 -0.111675 17 1.627912 0.043611 1.743403 -0.012714 18 0.693458 0.144327 0.329500 -0.655045 19 0.104425 0.037412 0.450598 -0.923387 df.drop([3, 5, 8, 10, 18], inplace=True) df A B C D 0 -0.761269 0.477348 1.170614 0.752714 1 1.217250 -0.930860 -0.769324 -0.408642 2 -0.619679 -1.227659 -0.259135 1.700294 4 -0.529529 0.000571 0.913779 1.395894 6 0.757178 0.240012 -0.553820 1.177202 7 -0.986128 -1.313843 0.788589 -0.707836 9 -0.692013 0.671866 1.179466 -1.180351 11 -0.143273 -0.503199 -1.328728 0.610552 12 -0.923110 -1.365890 -1.366202 -1.185999 13 -2.026832 0.273593 -0.440426 -0.627423 14 -0.054503 -0.788866 -0.228088 -0.404783 15 0.955298 -1.430019 1.434071 -0.088215 16 -0.227946 0.047462 0.373573 -0.111675 17 1.627912 0.043611 1.743403 -0.012714 19 0.104425 0.037412 0.450598 -0.923387 df.loc[:, 'NewCol'] = 0 df A B C D NewCol 0 -0.761269 0.477348 1.170614 0.752714 0 1 1.217250 -0.930860 -0.769324 -0.408642 0 2 -0.619679 -1.227659 -0.259135 1.700294 0 4 -0.529529 0.000571 0.913779 1.395894 0 6 0.757178 0.240012 -0.553820 1.177202 0 7 -0.986128 -1.313843 0.788589 -0.707836 0 9 -0.692013 0.671866 1.179466 -1.180351 0 11 -0.143273 -0.503199 -1.328728 0.610552 0 12 -0.923110 -1.365890 -1.366202 -1.185999 0 13 -2.026832 0.273593 -0.440426 -0.627423 0 14 -0.054503 -0.788866 -0.228088 -0.404783 0 15 0.955298 -1.430019 1.434071 -0.088215 0 16 -0.227946 0.047462 0.373573 -0.111675 0 17 1.627912 0.043611 1.743403 -0.012714 0 19 0.104425 0.037412 0.450598 -0.923387 0 |
如果数据帧和序列对象具有相同的索引,那么
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | import pandas as pd df # a b c d #0 0.671399 0.101208 -0.181532 0.241273 #1 0.446172 -0.243316 0.051767 1.577318 #2 0.614758 0.075793 -0.451460 -0.012493 e = pd.Series([-0.335485, -1.166658, -0.385571]) e #0 -0.335485 #1 -1.166658 #2 -0.385571 #dtype: float64 # here we need to give the series object a name which converts to the new column name # in the result df = pd.concat([df, e.rename("e")], axis=1) df # a b c d e #0 0.671399 0.101208 -0.181532 0.241273 -0.335485 #1 0.446172 -0.243316 0.051767 1.577318 -1.166658 #2 0.614758 0.075793 -0.451460 -0.012493 -0.385571 |
如果它们没有相同的索引:
1 2 | e.index = df.index df = pd.concat([df, e.rename("e")], axis=1) |
简单易行的方法
在分配新列之前,如果有索引数据,则需要对索引进行排序。至少在我的情况下,我必须:
1 2 3 4 | data.set_index(['index_column'], inplace=True) "if index is unsorted, assignment of a new column will fail" data.sort_index(inplace = True) data.loc['index_value1', 'column_y'] = np.random.randn(data.loc['index_value1', 'column_x'].shape[0]) |
不过,要注意的一点是,如果你这样做了
1 | df1['e'] = Series(np.random.randn(sLength), index=df1.index) |
这实际上是df1.index上的左联接。因此,如果您想要有一个外部连接效果,我可能不完美的解决方案是创建一个包含索引值的数据框架,该索引值覆盖了您的数据世界,然后使用上面的代码。例如,
1 2 | data = pd.DataFrame(index=all_possible_values) df1['e'] = Series(np.random.randn(sLength), index=df1.index) |
我再补充一句,就像hum3一样,
还要注意,如果您知道自己在做什么,可以使用
我在寻找一种一般的方法,在不使用哑的
从以下内容:
- 这里的答案
- 关于将变量作为关键字参数传递的问题
- 此方法用于生成一个由NAN组成的
numpy 阵列
我想到了这个:
1 2 | col = 'column_name' df = df.assign(**{col:numpy.full(len(df), numpy.nan)}) |
为了完整性-还有另一个使用dataframe.eval()方法的解决方案:
数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | In [44]: e Out[44]: 0 1.225506 1 -1.033944 2 -0.498953 3 -0.373332 4 0.615030 5 -0.622436 dtype: float64 In [45]: df1 Out[45]: a b c d 0 -0.634222 -0.103264 0.745069 0.801288 4 0.782387 -0.090279 0.757662 -0.602408 5 -0.117456 2.124496 1.057301 0.765466 7 0.767532 0.104304 -0.586850 1.051297 8 -0.103272 0.958334 1.163092 1.182315 9 -0.616254 0.296678 -0.112027 0.679112 |
解决方案:
1 2 3 4 5 6 7 8 9 10 11 | In [46]: df1.eval("e = @e.values", inplace=True) In [47]: df1 Out[47]: a b c d e 0 -0.634222 -0.103264 0.745069 0.801288 1.225506 4 0.782387 -0.090279 0.757662 -0.602408 -1.033944 5 -0.117456 2.124496 1.057301 0.765466 -0.498953 7 0.767532 0.104304 -0.586850 1.051297 -0.373332 8 -0.103272 0.958334 1.163092 1.182315 0.615030 9 -0.616254 0.296678 -0.112027 0.679112 -0.622436 |
将新列"e"添加到现有数据帧
1 | df1.loc[:,'e'] = Series(np.random.randn(sLength)) |
以下是我所做的…但我对大熊猫和Python还很陌生,所以没有任何承诺。
1 2 3 4 5 6 7 8 9 10 | df = pd.DataFrame([[1, 2], [3, 4], [5,6]], columns=list('AB')) newCol = [3,5,7] newName = 'C' values = np.insert(df.values,df.shape[1],newCol,axis=1) header = df.columns.values.tolist() header.append(newName) df = pd.DataFrame(values,columns=header) |
如果你得到了
1 2 | df = df.copy() df['col_name'] = values |
要在数据帧的给定位置(0<=loc<=amount of columns)插入新列,只需使用数据帧。插入:
1 | DataFrame.insert(loc, column, value) |
因此,如果要在名为df的数据帧末尾添加列e,可以使用:
1 2 | e = [-0.335485, -1.166658, -0.385571] DataFrame.insert(loc=len(df.columns), column='e', value=e) |
值可以是一个系列、一个整数(在这种情况下,所有单元格都会填充这个值)或类似数组的结构。
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.dataframe.insert.html