pandas 添加列以反映值的出现次数

qhhrdooz  于 2023-03-11  发布在  其他
关注(0)|答案(1)|浏览(153)

我有一个排序后的 Dataframe ,如下所示:
| 姓名|年份|价格|
| - ------|- ------|- ------|
| 项目a|二○一九年|十个|
| 项目a|小行星2020|二十个|
| 项目a|小行星2021|三十|
| B|二〇一五年|五十五|
| B|二○一九年|七十五|
| (c)秘书长的报告|二○一一年|十五|
我想添加更多与“Name”出现次数对应的“Price”列,这样 Dataframe 就可以如下所示:
| 姓名|年份|价格|价格_2|价格_3|
| - ------|- ------|- ------|- ------|- ------|
| 项目a|二○一九年|十个|无|无|
| 项目a|小行星2020|二十个|十个|无|
| 项目a|小行星2021|三十|十个|二十个|
| B|二〇一五年|五十五|无|无|
| B|二○一九年|七十五|五十五|无|
| (c)秘书长的报告|二○一一年|十五|无|无|
例如,'a'的第一个示例的价格为10。'a'的第二个示例的价格为20。我想添加一列来反映'a'的第一个示例的价格,即10。
一个名称在我的数据集中出现的最大次数是4,因此添加太多列应该不是问题。
我试着创建一个出现2次的名字列表,一个出现3次的名字列表,等等。然后我试着将这些列表附加到 Dataframe 。尽管这里的问题是在正确的位置添加0,以便列表适当地附加。
我已经为此挣扎了一段时间了,因为我还在适应Python和Pandas。
预先感谢你的帮助。

5uzkadbs

5uzkadbs1#

下面是一个严重依赖列表/数组和.apply()方法的解决方案:

输入数据

import pandas as pd
import numpy as np

data = {
    'Name': ['a', 'a', 'a', 'b', 'b', 'c'],
    'Year': [2019, 2020, 2021, 2015, 2019, 2011],
    'Price': [10, 20, 30, 55, 75, 15]
}

df = pd.DataFrame(data)
df = df.sort_values(['Name', 'Year'])

print(df)
Name  Year  Price
0    a  2019     10
1    a  2020     20
2    a  2021     30
3    b  2015     55
4    b  2019     75
5    c  2011     15

步骤1:累计追加清单中的价格

首先,使用.groupby()Name字段对DataFrame行进行分组。
然后对每个组的Price字段使用.apply()方法两次,嵌套一次将每个价格转换为列表,外部一次使用.cumsum()方法对它们执行运行“求和”。
为了确保列表的顺序正确(根据您想要的输出),还可以使用.apply(),将最近附加的值放在前面。

# Group by name
name_groups= df.groupby('Name')

# For each name group, cumulatively append the prices in lists
price_lists = name_groups['Price'].apply(lambda gp: gp.apply(
                                             lambda p: [p]).cumsum()
                                        ).apply(lambda x: [x[-1]] + x[0:-1])

print(price_lists)

电流输出:

0            [10]
1        [20, 10]
2    [30, 10, 20]
3            [55]
4        [75, 55]
5            [15]
Name: Price, dtype: object

第二步:用零填充这些表

要计算DataFrame的price列的最大数量,请找出重复名称的最大数量(在本例中,该值为3,因为'a'的重复名称最多,总共有三个)。
然后对每个列表使用np.pad(),使它们的长度都与该值匹配,并在右侧填充零。

# Get the highest number of name duplicates.
max_names = max(name_groups.size())

# Pad each of these lists with zeros (as a numpy array), having a length equal to max_names
price_arrays = price_lists.apply(lambda x: np.pad(x, [0, max_names - len(x)]))

print(price_arrays)

电流输出:

0      [10, 0, 0]
1     [20, 10, 0]
2    [30, 10, 20]
3      [55, 0, 0]
4     [75, 55, 0]
5      [15, 0, 0]
Name: Price, dtype: object

步骤3:将值作为单独的列添加到DataFrame中

指定将分别表示每个列表元素的列标签。
然后用列表值创建一个新的DataFrame,确保使用.tolist()方法将它们作为列表/数组的列表传递。
从那里,您可以将这些列添加到原始DataFrame中指定的列名下。

# Generate the column names to store the results under.
cols = ['Price'] + [f'Price_{i}' for i in range(2, max_names + 1)]

# Add the values to the DataFrame under these column names
df[cols] = pd.DataFrame(price_arrays.tolist())

print(df)

最终输出:

Name  Year  Price  Price_2  Price_3
0    a  2019     10        0        0
1    a  2020     20       10        0
2    a  2021     30       10       20
3    b  2015     55        0        0
4    b  2019     75       55        0
5    c  2011     15        0        0

完整代码:

# --- Step 1 ---
name_groups = df.groupby('Name')
price_lists = name_groups['Price'].apply(lambda gp: gp.apply(
                                             lambda p: [p]).cumsum()
                                        ).apply(lambda x: [x[-1]] + x[0:-1])

# --- Step 2 ---
max_names = max(name_groups.size())
price_arrays = price_lists.apply(lambda x: np.pad(x, [0, max_names - len(x)]))

# --- Step 3 ---
cols = ['Price'] + [f'Price_{i}' for i in range(2, max_names + 1)]
df[cols] = pd.DataFrame(price_arrays.tolist())

相关问题