如何使用 pandas DataFrame 计算列表的字典?

Posted

技术标签:

【中文标题】如何使用 pandas DataFrame 计算列表的字典?【英文标题】:How to calculate dictionaries of lists using pandas DataFrame? 【发布时间】:2019-02-08 03:06:17 【问题描述】:

我在Python3.x中有两个字符串,定义为相同长度:

string1 = 'WGWFTSJKPGP'
string2 = 'DORKSRQKYJG'

我还得到了一个整数,它表示string2 的“起始索引”。在这种情况下,start_pos = 51

目标是根据索引创建字典。所以,string1 开始于0string2 开始于51。字典“转换”这些坐标如下:

0: 51, 1: 52, 2: 53, 3: 54, 4: 55, 5: 56, 6: 57, 7: 58, 8: 59, 9: 60, 10: 61

可以通过以下方式构造(给出上面的变量):

convert_dict = i: i + start_pos for i, _ in enumerate(string1)

我目前以 pandas DataFrame 的形式拥有这些数据:

import pandas as pd

dict1 = 'column1':['MXRBMVQDHF', 'LJNVTJOY', 'LJNVTJOY', 'LJNVTJOY', 'WHLAOECVQR'], 'column2':['DPBVNJYANX', 'UWRAWDOB', 'PEKUYUQR', 'WPMLFVFZ', 'CUTQVWHRIJ'], 'start':[79, 31, 52, 84, 18]

df = pd.DataFrame(dict1)
print(df)
#       column1     column2  start
# 0  MXRBMVQDHF  DPBVNJYANX     79
# 1    LJNVTJOY    UWRAWDOB     31
# 2    LJNVTJOY    PEKUYUQR     52
# 3    LJNVTJOY    WPMLFVFZ     84
# 4  WHLAOECVQR  CUTQVWHRIJ     18

column1 列中有多个相同字符串的条目。在这种情况下,LJNVTJOY 坐标的字典应该是:

0: [31, 52, 84], 1: [32, 53, 85], 2: [33, 54, 86], 3: [34, 55, 87], 
     4: [35, 56, 88], 5: [36, 57, 89], 6: [37, 58, 90], 7: [38, 59, 91]

我想使用这个 DataFrame 并计算类似的坐标字典。这样的.groupby('column1') 声明看起来应该以某种方式使用.apply()?我不确定如何填充这样的字典列表...

这是正确的输出(保持 DataFrame 结构)。在这里,DataFrame df2 具有列 'new_column',如下所示:

df2.new_column
0    0: 79, 1: 80, 2: 81, 3: 82, 4: 83, 5: 84, 6: ...
1    0: [31, 52, 84], 1: [32, 53, 85], 2: [33, 54, 86], 3: [34, 55, 87], 4: [35, 56, 88], 5: [36, 57, 89], 6: [37, 58, 90], 7: [38, 59, 91]
2    0: 52, 1: 53, 2: 54, 3: 55, 4: 56, 5: 57, 6: ...
Name: new, dtype: object

【问题讨论】:

【参考方案1】:

使用 -

def dict_op(x):
    string1 = x['column1']
    string2 = x['column2']
    start_pos = x['start']
    x['val'] = i: i + start_pos for i, _ in enumerate(string1)
    return x

def zip_dict(x):
    b=pd.DataFrame(x)
    return i:b.loc[:,i].tolist() for i in b.columns 

op = df.apply(dict_op, axis=1).groupby('column1')['val'].apply(list).apply(zip_dict)
print(op)

输出

column1
LJNVTJOY      0: [31, 52, 84], 1: [32, 53, 85], 2: [33, 54,...
MXRBMVQDHF    0: [79], 1: [80], 2: [81], 3: [82], 4: [83], ...
WHLAOECVQR    0: [18], 1: [19], 2: [20], 3: [21], 4: [22], ...
Name: val, dtype: object

说明

dict_op 重用您的代码为每一行创建字典,然后 .apply(list) 将字典压缩在一起以形成字典列表。

zip_dict() 然后从临时输出中创建输出dict

我没有包含的最后一部分是如果列表的长度为 1 则您可以仅包含第一个元素,将输出从 0: [79], 1: [80], 2: [81], 3: [82], 4: [83], ... 获取到 0: 79, 1: 80, 2: 81, 3: 82, 4: 83, ...

【讨论】:

【参考方案2】:

首先应用 groupby 函数将“开始”列聚合为列表

df2 = df.groupby("column1")["start"].apply(list).reset_index()

现在,您可以编写一个函数来创建新的字典列

def create_dict(row):
    new_dict = 
    for i, j in enumerate(row["column1"]):
        if len(row["start"]) == 1:
            new_dict[i] = row["start"][0]+i
        else:
            for k in row["start"]:
                if i in new_dict:
                    new_dict[i].append(k + i)
                else:
                    new_dict[i] = [k + i]
    return new_dict

最后,将这个函数应用到df2的所有行

df2["new_column"] = df2.apply(create_dict, axis = 1)

【讨论】:

【参考方案3】:

这是一个稍微不同的方法,使用一个lambda 和两个zips

df2 = df.groupby('column1')['start'].agg([('s', list)]).reset_index()
df2['l'] = df.column1.str.len()

df2.apply(lambda x: dict(zip(range(x['l'] + 1), zip(*[range(s, s + x['l'] + 1) for s in x['s']]))), axis = 1)

可以在这里看到截断的输出(注意它返回元组而不是列表):

0    0: (31, 52, 84), 1: (32, 53, 85), 2: (33, 54,...
1    0: (79,), 1: (80,), 2: (81,), 3: (82,), 4: (8...
2    0: (18,), 1: (19,), 2: (20,), 3: (21,), 4: (2...

首先,要缩短apply 步骤的长度,请创建一个包含column1 值和相关起始位置的DataFrame。另外,添加一个长度为column1 的列(假设等长断言成立)。

之后,将column1 字母索引的范围(0len(column1),用作键,以及由start 值偏移的相同范围组合起来。

第二个zip 有点冒险,因为[range(s, s + x['l'] + 1) for s in x['s']] 返回的东西看起来像这样(对于'LJNVTJOY'):

[[31, 32, 33, 34, 35, 36, 37, 38, 39],
 [52, 53, 54, 55, 56, 57, 58, 59, 60],
 [84, 85, 86, 87, 88, 89, 90, 91, 92]]

当我们真的想对垂直对齐的元素进行分组时,我们使用“splat”或“unpacking”运算符将这些列表输入zip。一旦我们组合了这些列表,我们就有了一个键列表和一个(元组)值列表,可以将 zipped 转换为 dict

【讨论】:

以上是关于如何使用 pandas DataFrame 计算列表的字典?的主要内容,如果未能解决你的问题,请参考以下文章

pandas计算dataframe结束时间列和起始时间列的时间差使用sort_values函数对dataframe数据基于时间差进行排序(设置使用倒序排序)

pandas计算dataframe结束时间列和起始时间列的时间差使用sort_values函数对dataframe数据基于时间差进行排序(默认为升序排序)

pandas使用unique函数计算dataframe单个数据列中的独特值或者计算dataframe多个数据列的独特值(get unique values of column or columns)

pandas使用ewm函数计算dataframe指定数据列的的特定周期指数移动(滚动)平均(Exponential Moving Average)

pandas使用sum函数计算dataframe单数据列的加和或者对所有的数据列进行求和(sum column or all columns of dataframe)

pandas使用to_datetime函数将字符串时间数据列转化为时间对象数据列计算dataframe结束时间列和起始时间列的时间差并计算时间差的均值